
背景知識使用 Delphi 的 WebBroker 框架可以開發(fā)標(biāo)準(zhǔn)的 Web Server 程序。使用 Delphi 的 SOAP 框架可以開發(fā)支持 SOAP 標(biāo)準(zhǔn)的 WebService 服務(wù)端程序。此框架建立的 WebBroker 框架之上。使用 Delphi 可以開發(fā)客戶端程序去調(diào)用 WebService 服務(wù)器提供的 SOAP 函數(shù)。同時也可以去調(diào)用 WebBroker 開發(fā)的 Web Server 提供的 RESTfull 的 URL 接口。問題WebBroker 的架構(gòu)下客戶端和服務(wù)器端沒有長連接是無狀態(tài)的。也就是服務(wù)器端并不能記住客戶端的上一次訪問。因此需要一個 Session 機(jī)制。因?yàn)槭?Web 訪問可以采用 HTTP Cookie 來讓客戶端和服務(wù)器端之間維護(hù)一個 Session。這個方式的好處是客戶端基本上不需要寫代碼。但是如果應(yīng)用程序的代碼框架比較復(fù)雜比如同一個客戶端可能需要訪問多個不同的 WebService 服務(wù)器端甚至同時還要訪問多個 WebBroker 的 WebServer 服務(wù)器端。此時Cookie 因?yàn)椴荒芸缬驈囊粋€ WebService 服務(wù)器端程序獲得的 HTTP Cookie 無法讓另外一個服務(wù)器端程序讀到。如果要在多個 WebService 服務(wù)器端程序之間保持同一個 Session則需要考慮使用另外兩種方式1. 在 URL 里面加上 Session 有關(guān)的參數(shù)2. 在 HTTP Header 里面加上 Session 有關(guān)的參數(shù)使用 HTTP Header 來維護(hù) Session 的代碼實(shí)現(xiàn)客戶端客戶端如果使用 HTTRIO 去調(diào)用服務(wù)器端的函數(shù)設(shè)計(jì)期選中 HTTPRIO1屬性面板里面事件標(biāo)簽頁HTTPWebNode 下拉開找到OnBeforePost事件雙擊產(chǎn)生事件方法代碼uses Soap.SOAPHTTPTrans; procedure TForm2.HTTPRIO1HTTPWebNode1BeforePost(const HTTPReqResp: THTTPReqResp; Client: THTTPClient); begin Client.CustomHeaders[ABC] : abcdexyz; end;則每次使用這個 httpRIO1 來調(diào)用服務(wù)器端方法時都會為 HTTP 加上一個名字為 abc 的 HeaderSoapConnection 的問題是它內(nèi)部的 RIO 不是一直存在的。為它設(shè)置了 URL 以后需要設(shè)置它的 Connected 屬性為 True這個 RIO 才會被創(chuàng)建出來。因此代碼可能需要顯示地執(zhí)行 SoapConnection1.Connected : True; 然后再判斷是否有 RIO如果有則執(zhí)行以下代碼綁定事件SoapConnection1.RIO.HTTPWebNode.OnBeforePost : TForm2.HTTPRIO1HTTPWebNode1BeforePost;這樣綁定后SoapConnection 和 HTTPRIO 應(yīng)該就能共享同一個 HTTP Header 的代碼了。以下代碼測試通過procedure TForm2.Button2Click(Sender: TObject); begin SoapConnection1.Connected : True; if Assigned(SoapConnection1.RIO) then begin SoapConnection1.RIO.HTTPWebNode.OnBeforePost : HTTPRIO1HTTPWebNode1BeforePost; end; ClientDataSet1.Close; ClientDataSet1.Open; end;服務(wù)器端服務(wù)器端在接口方法的實(shí)現(xiàn)里面直接讀取 HTTP Header: 的代碼uses SOAP.WebBrokerSOAP, web.HttpApp; { TtestHeader } function TtestHeader.testHeader: string; begin Result : GetSOAPWebModule.Request.GetFieldByName(abc); end;服務(wù)器端的 Soap Data Module對應(yīng)客戶端的 SoapConnection 當(dāng)客戶端的 ClientDataSet.Open 的時候服務(wù)器端的 DataSetProvider.BeforeGetRecords 事件里面寫代碼讀 Header 是否正確代碼如下uses SOAP.WebBrokerSOAP, web.HttpApp; {$R *.DFM} procedure TMyDataCreateInstance(out obj: TObject); begin obj : TMyData.Create(nil); end; function TMyData.CheckHeader: Boolean; begin Result : abcdexyz GetSOAPWebModule.Request.GetFieldByName(abc); end; procedure TMyData.DataSetProvider1BeforeGetRecords(Sender: TObject; var OwnerData: OLEVariant); begin if not CheckHeader then raise Exception.Create(身份驗(yàn)證沒通過); end;總之服務(wù)器端不管是接口方法的實(shí)現(xiàn)部分還是 SoapDataModule 里面都是調(diào)用GetSOAPWebModule.Request.GetFieldByName(abc);去讀取 Header 來獲得客戶端提交的 Session ID 或者說 Token客戶端使用 IdHTTPprocedure TForm2.Button3Click(Sender: TObject); var S: string; begin IdHTTP1.Request.CustomHeaders.Values[abc] : abcde; S : IdHTTP1.Get(http://localhost:8080/MyHeader); Log(S); end;上述代碼使用 TIdHTTP 作為 HTTP 客戶端去請求一個 WebBroker 服務(wù)器端的 MyHeader 路徑。請求之前添加了一個自定義的 CustomHeader然后WebBroker 服務(wù)器端對應(yīng)的代碼通過以下方法讀客戶端傳過來的 HTTP Headerprocedure TWebModule1.WebModule1MyHeaderAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); var S: string; begin S : Request.GetFieldByName(abc); Response.Content : S; end;