使用RTC调用WebService WebService的协议 WebService协议,就目前来说基本上是一个已经趋于过时的东西了,目前最主流的微服务端SDK都基本上采用了Restful的方式来作为交互模型,其最主要的原
使用RTC调用WebService
WebService的协议
WebService协议,就目前来说基本上是一个已经趋于过时的东西了,目前最主流的微服务端SDK都基本上采用了Restful的方式来作为交互模型,其最主要的原因是应该是WebService传递数据的冗余性比较高。虽然已经趋于过时了,但是不少的服务还是采用了WebService来作为API的服务提供者,就拿我们公司来说,本来我是让Web组的别用WebService作为服务API来提供服务的,但是Web组的说,WebService他写起来最简单,特么的C#中直接[WebMethod]标记一下就作为WebService服务了,编写起来确实很方便,所以估计我想很多人估计也是类似的想法了。 说了这么多,其实都是废话哈哈,继续回到其协议上来说,WebService使用的是SOAP协议,soap协议只是用来封装消息用的。封装后的消息你可以通过各种已有的协议来传输,比如http,tcp/ip,smtp,等等,你甚至还一次用自定义的协议,当然也可以用https协议。那么WebService自然就是Http版本的SOAP传递数据了,说白了就是使用Http提交Xml格式数据,没啥太多的玄机在里面,知道了WebService就是Http提交XML数据之后,我们可做的事情就很简单了,那么就是模拟Http提交Xml数据就完事了呗,这个提交比较简单,麻烦的就是对于这个提交的Xml数据的构造上,这个就可以去看SOAP的协议格式文档了。其协议格式,记得是有有2个版本,一个SOAPV1,还有一个V2,两个的投递方式有一点区别,具体是啥的,好像是SOAPV1 Http投递的时候,HttpHeader中需要带上SOAPAction这个参数还是啥的,忘了,这个可以查看相关的协议文档。其投递的格式基本上类似如下:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:WebServiceFuncName xmlns:m="Some-URI">
<symbol>DIS</symbol>
</m:WebServiceFuncName>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
也有类似这种的
<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://webservice.hisinterface.hzyl.aspirecn.com/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<ns1:Body>
<ns0:ObjectParam>
<arg0>%s</arg0>
<arg1>%s</arg1>
</ns0:ObjectParam>
</ns1:Body>
</SOAP-ENV>
调用WebService
WebService在Delphi中,其实Delphi是提供了调用WebService的方法的,这种Delphi自带的调用模式,我就不讲了,用起来比较简单,不过有一点很蛋疼,就是对于某些WebService,使用Delphi自带的方式自动创建的调用模式会各种调用失败,记得一直到XE7的版本都不行,更高的版本就不知道行不行了,一直使用RTC来模拟提交Http的一些相关请求,于是想到用WebService来做处理,根据前面的分析,已经很清楚了,只要构建好要投递的WebService的Xml内容,那么模拟提交就很简单了,至于这个模拟投递的内容如何处理,可以根据SOAP的协议格式来做处理,一般是
<m:WebServiceFuncName xmlns:m="WebServiceNameSpace">
<Param1>参数1</Param1>
<Param2>参数2</Param2>
</m:WebServiceFuncName>
这种方式,也有传递对象的方式的,就是前面说的那种方式,总之根据协议格式去构建出Xml数据就能提交了。提交试用RtcDataRequest和RtcHttpClient
*delphi
const
poststr = '<?xml version="1.0" encoding="utf-8"?>'#13#10+
'<SOAP-ENV:Envelope xmlns:ns0="http://webservice.hisinterface.hzyl.aspirecn.com/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">'#13#10+
'<ns1:Body>'#13#10+
'<ns0:request>'#13#10+
' <arg0>%s</arg0>'#13#10+
' <arg1>%s</arg1>'#13#10+
'</ns0:request>'#13#10+
'</ns1:Body>'#13#10+
'</SOAP-ENV>';
procedure TForm1.Button1Click(Sender: TObject);
var
Head,Body: string;
begin
Body := '<body><oldPasswd>123456</oldPasswd><newPasswd>23423</newPasswd></body>';
Head := '<head><operCode>S02</operCode><rsa>Edsuyufjewur038jfkfur74kfr449</rsa></head>';
Head := stringReplace(Head,'<','<',[rfReplaceAll]);
Head := stringReplace(Head,'>','>',[rfReplaceAll]);
Body := stringReplace(Body,'<','<',[rfReplaceAll]);
Body := stringReplace(Body,'>','>',[rfReplaceAll]);
RtcDataRequest1.Tag := 0;
RtcDataRequest1.Request.Method:='POST';
RtcDataRequest1.Request.FileName:= '/hisinterface/service/request';
RtcDataRequest1.Request.Host:=RtcHttpClient1.ServerAddr;
RtcDataRequest1.Request.ContentType := 'application/soap+xml; charset=utf-8';
RtcDataRequest1.Request.HeaderText:=RtcDataRequest1.Request.HeaderText+#13#10+'SOAPAction=http://218.201.202.252/hisinterface/service/request';
self.RtcDataRequest1.Request.Params.Text := Format(poststr,[Head,Body]);
self.RtcDataRequest1.Post();
if self.RtcDataRequest1.WaitForCompletion() then
begin
Head := RtcDataRequest1.Client.Read;
xmldocument1.LoadFromXML(Head);
Memo1.Lines.Text := xmldocument1.ChildNodes[0].ChildNodes[0].ChildNodes[0].ChildNodes[0].Text;
end;
end;
procedure TForm1.RtcDataRequest1BeginRequest(Sender: TRtcConnection);
var
Cli:TRtcDataClient absolute Sender;
begin
Cli.Write(Cli.Request.Params.Text);
end;
以上的代码是测试调用某公司的医保信息服务器的代码
那么,我们可以写一个比较通用的调用WebService的函数,完整代码如下,直接使用里面的
CallWebService则可用Rtc调用WebService
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, rtcConn, rtcDataCli,
rtcHttpCli, rtcInfo,System.Generics.Collections;
type
TForm1 = class(TForm)
RtcDataRequest1: TRtcDataRequest;
RtcHttpClient1: TRtcHttpClient;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure DoBeginRequest(Sender: TRtcConnection);
procedure DoDataSent(Sender: TRtcConnection);
procedure CallWebService(Url: string;MethodName: string;Params: TDictionary<string, string>;WebServiceNameSpace: string);
end;
var
Form1: TForm1;
implementation
uses QString,Qxml;
const MAX_SEND_Block_Size = 1460*44;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
params: TDictionary<string, string>;
begin
params := TDictionary<string, string>.Create();
params.AddOrSetValue('byProvinceName','北京');
CallWebService('http://www.webxml.com.cn/WebServices/WeatherWebService.asmx','getSupportCity',params,'http://WebXml.com.cn/');
params.Free;
end;
procedure TForm1.CallWebService(Url, MethodName: string; Params: TDictionary<string, string>; WebServiceNameSpace: string);
function CreateWebServicePost: string;//构建WebService的提交数据
var
pair: TPair<string, string>;
st: string;
begin
if WebServiceNameSpace = '' then
WebServiceNameSpace := 'http://tempuri.org/';
Result := '<?xml version="1.0" encoding="utf-8"?>'#13#10+
'<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">'#13#10+
' <soap12:Body>'#13#10+
' <'+MethodName+' xmlns="'+WebServiceNameSpace+'">'#13#10;
for pair in Params do
begin
st := pair.Key;
if CompareText('SUBMIT',st) <> 0 then
Result := Result + ' <'+st+'>'+rtcInfo.Utf8Encode(pair.Value)+ '</'+st+'>'#13#10
end;
result := result +
' </'+MethodName+'>'#13#10+
' </soap12:Body>'#13#10+
'</soap12:Envelope>';
end;
var
st,srv,port: string;
xml,rNode: TQxmlNode;
begin
st := LowerCase(Url);
if Pos('http://',st) <> 0 then
st := Copy(st,8,MaxInt);
srv := qstring.DecodeTokenW(st,'/','''',true,true);
Url := st;
st := qstring.DecodeTokenW(srv,':','''',true,true);
if srv <> '' then
begin
port := srv;
end
else
begin
port := '';
end;
srv := st;
url := '/'+url;
RtcHttpClient1.ServerAddr := srv;
if port = '' then
RtcHttpClient1.ServerPort := '80'
else RtcHttpClient1.ServerPort := port;
RtcHttpClient1.AutoConnect := true;
RtcHttpClient1.MultiThreaded := true;
RtcHttpClient1.ReconnectOn.ConnectLost := true;
RtcDataRequest1.Client := RtcHttpClient1;
RtcDataRequest1.Request.Host := srv;
RtcDataRequest1.OnBeginRequest := DoBeginRequest;
RtcDataRequest1.OnDataSent := DoDataSent;
RtcDataRequest1.Request.Params.Clear;
//Request.Request.ItemName['SOAPAction'] := ''; //SOAP1.1,需要指定这个
RtcDataRequest1.Request.FileName := url;
RtcDataRequest1.Request.Params.Text := CreateWebServicePost;
RtcDataRequest1.Request.ContentType := 'application/soap+xml; charset=utf-8';
RtcDataRequest1.Request.Method := 'POST';
RtcDataRequest1.Post; //提交内容
if RtcDataRequest1.WaitForCompletion(False,30000) then //等待返回
begin
st := rtcInfo.Utf8Decode(RtcDataRequest1.Client.read);
xml := TQXMLNode.Create;
try
xml.Parse(st);
rNode := xml.ItemByPath('soap12:Envelope.soap12:Body.'+MethodName+'Response.'+MethodName+'.Result');
if rNode <> nil then
st := rNode.Text
else st := xml.Text;
except
on e: exception do
begin
st := st + '无效地XML返回';
end;
end;
xml.Free;
ShowMessage(st);
end;
end;
procedure TForm1.DoBeginRequest(Sender: TRtcConnection);
var
st: RtcString;
ilen: integer;
begin
with TRtcDataClient(Sender) do
begin
if Request.Method = 'POST' then
begin
st := Request.Params.Text;
ilen := Length(st);
Request.ContentLength := ilen;
if ilen <= MAX_SEND_Block_Size then
Write(st)
else
begin
Write(Copy(st,1,MAX_SEND_Block_Size));
st := Copy(st,1+MAX_SEND_Block_Size,MaxInt);
Request.Info['WillSend'] := st; //将要发送的
end;
end
else
WriteHeader();
end;
end;
procedure TForm1.DoDataSent(Sender: TRtcConnection);
var
ilen: integer;
st: RtcString;
begin
with TRtcDataClient(Sender) do
begin
if Request.ContentLength>Request.ContentOut then
begin
ilen := Request.ContentLength-Request.ContentOut;
st := Request.Info['WillSend'];
if ilen <= MAX_SEND_Block_Size then
Write(st)
else
begin
Request.Info['WillSend'] := Copy(st,1+MAX_SEND_Block_Size,MaxInt);
Write(Copy(st,1,MAX_SEND_Block_Size));
end;
end;
end;
end;
end.