Delphi Soap WebService 的 HTTP Cookies

前情提要:

Delphi SOAP WebService 服务器端多个 SoapDataModule 的做法

Delphi 写 WebService 架构的三层程序如何维护 Session

Delphi 的 WebService 的 Cookie 操作

 

问题起因

在使用 Delphi 开发 SOAP WebService 服务器端和客户端的过程中,我们可以使用 HTTP Cookies 来实现用户身份验证,或者一些【状态】的传递,而客户端基本上不需要写代码。采用其它方法,每次客户端需要和服务器端交互的时候,都需要使用代码向服务器端传递登录身份信息。而使用 HTTP Cookies,只需要客户端调用一次服务器端的【登录】方法,服务器端在该方法中,为客户端创建一个 HTTP Cookie;以后每次客户端的访问,服务器端都可以读到该 Cookie,用以知道客户端的登录信息。

在客户端,可能同时有多个 HTTPRIO 和 SoapConnection,这个是为了代码编写方便。上述对于 Cookies 的操作,在 Delphi 7 底下没有问题。

到了新版的 Delphi,可能是因为其 SOAP 架构底下的 HTTP 部分的代码重写了的原因,使用 HTTPRIO1 去执行服务器端方法获得的 Cookie,使用 SoapConnection1 去调用服务器端方法时(比如执行 ClientDataSet1.Open 方法),服务器端却读不到客户端的 Cookie;说明两个对象实例,没有共享来自服务器端的 Cookie;

在 Delphi SOAP WebService 服务器端多个 SoapDataModule 的做法 这篇文章里面,因为我想用同一个 SoapConnection1 访问服务器端的多个 SoapDataModule,必须要:

  SoapConnection1.Connected := False;
  SoapConnection1.SOAPServerIID := '{52B5735F-378C-427E-8590-19C4704FAC94}'; // '{C99F4735-D6D2-495C-8CA2-E53E5A439E61}'; // '{F28A698B-98B0-DF8E-4977-6AE075489E81}';
  SoapConnection1.URL := 'http://localhost:8080/soap';
  SoapConnection1.Connected := True;

执行过上述代码后,即便 SoapConnection1 之前已经获得服务器端的 Cookie,再次去访问服务器的时候,服务器还是读不到来自客户端的 Cookie;

 

解决方法

还好,Delphi 提供了底层库的源代码。追踪 THTTPRIO 的源代码,找到了解决办法,也就是让客户端的多个 RIO 实例共享相同的来自服务器端的 Cookies 的办法。

首先,代码里面,需要 uses System.Net.HttpClient, Soap.SOAPHTTPTrans;  这个时 Delphi WebService 框架使用的 HTTP 的库。

在 System.Net.HttpClient 里面,THTTPClient 有一个 FCookieManager: TCookieManager;

而这个 FCookieManager 我们可以给它替换掉。

首先,我们在自己的程序里面声明一个自己的 FCookieManager: TCookieManager; 在程序启动的时候就创建它,直到程序退出才释放。用它作为各个 RIO 对象共享 Cookies 的对象。

然后,在 HTTPRIO 调用服务器端的方法之前:

HTTPRIO1.HTTPWebNode.HTTP.CookieManager := Self.FCookieManager;   //使用外部的 CookieManager 而不是 RIO 自己内部的。

在 SoapConnection1 切换了 SoapServerIID 之后:

procedure TForm1.Button6Click(Sender: TObject);
begin
  //测试服务器端有多个 SoapDataModule 的情况是否可以在客户端调用
  SoapConnection1.Connected := False;
  SoapConnection1.SOAPServerIID := '{52B5735F-378C-427E-8590-19C4704FAC94}'; // '{C99F4735-D6D2-495C-8CA2-E53E5A439E61}'; // '{F28A698B-98B0-DF8E-4977-6AE075489E81}';
  SoapConnection1.URL := 'http://localhost:8080/soap';
  SoapConnection1.Connected := True;

  SoapConnection1.RIO.HTTPWebNode.HTTP.CookieManager := Self.FCookieManager;

  ClientDataSet3.Open;
end;

解释一下上述代码:

SoapConnection1.Connected := False; 会使得 SoapConnection1 释放掉内部的 THTTPRIO 对象。真正执行 HTTP 操作的是这个 RIO 对象。即便之前 SoapConnection1 获得了服务器端的 Cookies,释放掉 RIO 对象以后,其内部也就没有了。

SoapConnection1.Connected := True; 则重新创建了其内部的 RIO 对象。

因此,需要在 Connected := True 后面,重新为其 RIO 对象,设置外部共享的 FCookieManager 对象。

 

结论:

通过上述方法,可以让客户端的多个 HTTPRIO 和 SoapConnection 共享来自服务器端 Cookies,使得客户端无需写传递信息的代码,自动向服务器传递由服务器事先创建的相关信息。最直接的使用场景,就是用户登录信息。

当然,服务器端不应该把用户名和密码放在 Cookies 里面,而是应该为每个客户端在登录时创建唯一的 Session 值,比如是一个唯一的 ID 等等,放在 Cookies 里面。这样每次客户端对服务器端的操作,在服务器端都能读到这个 Cookies 并且通过里面的 Session 值定位到这个是哪个客户端,完成登录后的客户端的身份认证。

之所以搞得如此麻烦,是因为 HTTP 访问是无状态的,服务器端并不知道当前访问的客户端,和之前访问的客户端,是不是同一个客户端。

如果采用 TCP 连接的方式的远程操作(Delphi 也有基于 TCP 长连接的三层数据库框架,比如 D7 时代的基于 Socket 的三层数据库框架,新版 Delphi 的 DataSnap 架构),在建立 TCP 连接的时候客户端提交用户名密码登录后,之后的每次操作,因为 TCP 连接一直保存,服务器端只要看是哪条 TCP 连接就知道是哪个客户端。但如果操作完成后 TCP 连接断开,则下次重新建立 TCP 连接后,服务器端是不知道这个客户端是谁的,客户端需要重新登录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值