使用RTC调用WebService

使用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>DISsymbol>
       m:WebServiceFuncName>
   SOAP-ENV:Body>
SOAP-ENV:Envelope>

也有类似这种的


   <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>%sarg0>
      <arg1>%sarg1>
   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>参数1Param1>
  <Param2>参数2Param2>  
m:WebServiceFuncName>

这种方式,也有传递对象的方式的,就是前面说的那种方式,总之根据协议格式去构建出Xml数据就能提交了。提交试用RtcDataRequest和RtcHttpClient
*delphi

const
  poststr = ''#13#10+
   ''#13#10+
   ''#13#10+
   ''#13#10+
   '   %s'#13#10+
   '   %s'#13#10+
   ''#13#10+
   ''#13#10+
   '';

procedure TForm1.Button1Click(Sender: TObject);
var
  Head,Body: string;
begin
  Body := '12345623423';
  Head := 'S02Edsuyufjewur038jfkfur74kfr449';

  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 := ''#13#10+
       ''#13#10+
       '  '#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+
       '  '#13#10+
       '';
  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.

你可能感兴趣的:(Delphi编程)