和indy要发生关系,经过了
TDSHTTPService.HttpServer-> TDSHTTPServerIndy.FServer -> IIPHTTPServer(TIdHTTPServerPeer).FHTTPServer -> TIdHTTPServerIP -> TIdHTTPServer目前TDSHTTPService并没有像TDSTCPServerTransport一样公布Indy的socket的OnConnect,OnDisconnect。所以要监视链接,得自己写代码。好在明白了上面的实现关系,代码就可以写成如下
(TDSHTTPServerIndy(DSHTTPService1.Server).Server as TIdHTTPServerPeer).FHTTPServer.OnConnect := procedure(AContext: TIdContext) begin end; 或者 (TDSHTTPServerIndy(DSHTTPService1.Server).Server as TIdHTTPServerPeer).SetOnConnect( procedure(AContext: IIPContext) begin end );遗憾的是,目前
方法1里Datasnap.DSHTTP单元的TDSHTTPServerIndy类并没有公开出来,TIdHTTPServerPeer的FHTTPServer是个私有变量
方法2里除了TDSHTTPServerIndy没公开外,TIdHTTPServerPeer的方法SetOnConnect是个protected。
上面的法子目前都不灵,只有走RTTI的hack方法来做。
在Datasnap.DSHTTP单元里,
procedure TDSHTTPServerIndy.InitializeServer; begin FServer.UseNagle := False; FServer.KeepAlive := True; FServer.ServerSoftware := 'DatasnapHTTPService/2011'; FServer.OnCommandGet := Self.DoIndyCommand; FServer.OnCommandOther := Self.DoIndyCommand; end;也就将TDSHTTPServerIndy.DoIndyCommand和TIdHTTPServer.OnCommandGet和TIdHTTPServer.OnCommandOther 给关联上了。目前的datasnap只关联了TIdHTTPServer的这两个事件。
剩下的就不必说了,TIdHTTPServer解析完了HTTP,给将数据给DoIndyCommand,DoIndyCommand再实施调度服务方法的工作。
TDSHTTPServer.DoCommand来进行任务分发工作,举其中一个类型JSON_CONTEXT来说明。
procedure TDSHTTPServer.DoJSONCommand(ARequestInfo: TDSHTTPRequest; AResponseInfo: TDSHTTPResponse; Request: String); begin if FCredentialsPassThrough then JSONService := TDSJSONService.Create(FDSServerName, FDSHostname, FDSPort, ARequestInfo.AuthUserName, ARequestInfo.AuthPassword, IPImplementationID) else JSONService := TDSJSONService.Create(FDSServerName, FDSHostname, FDSPort, FDSAuthUser, FDSAuthPassword, IPImplementationID); SessionID := GetRequestSessionId(aRequestInfo, True); ... case CmdType of hcGET: JSONService.ProcessGETRequest(Request, nil, ByteContent(ARequestInfo.PostStream), RespHandler); hcPOST: JSONService.ProcessPOSTRequest(Request, nil, ByteContent(ARequestInfo.PostStream), RespHandler); hcPUT: JSONService.ProcessPUTRequest(Request, nil, ByteContent(ARequestInfo.PostStream), RespHandler); hcDElETE: JSONService.ProcessDELETERequest(Request, nil, ByteContent(ARequestInfo.PostStream), RespHandler); else begin GetInvocationMetadata().ResponseCode := 501; GetInvocationMetadata().ResponseContent := Format(SCommandNotSupported, [ARequestInfo.Command]); end; end; ... if RespHandler = nil then FreeAndNil(JSONService); if RespHandler <> nil then RespHandler.Close; end; end; constructor TDSService.Create(dsServerName, dsHostname: String; dsPort: Integer; AuthUser, AuthPassword, AIPImplementationID: String); begin inherited Create; FDBXProperties := TDBXDatasnapProperties.Create(nil); if DSServerName = EmptyStr then //没指定了TDSHTTPService的Server时,就是用DSHostname, DSport建立DBXConnection,调用远程方法 begin FDBXProperties.Values[ TDBXPropertyNames.DriverName ] := DRIVER_NAME; FDBXProperties.Values[ TDBXPropertyNames.HostName ] := dsHostname; FDBXProperties.Values[ TDBXPropertyNames.Port ] := IntToStr( dsPort ); FLocalConnection := false; //不是本地连接 end else begin FDBXProperties.Values[ TDBXPropertyNames.DriverName ] := DSServerName; //指定了TDSHTTPService的Server时,就是自己的本地服务方法调用 FLocalConnection := true; //是本地的 end; FDBXProperties.DSAuthUser := AuthUser; FDBXProperties.DSAuthPassword := AuthPassword; FDBXProperties.Values[ TDBXPropertyNames.IPImplementationID ] := AIPImplementationID; StreamAsJSON := False; end;可以看到DoJSONCommand里面,新建立一个TDSService,然后执行了TDSService.Execute。也就是说,每次的HttpRequest请求,TDSHTTPServer都会建立一个全新的DBXConnection,连上TDSHTTPService的DSHostname,DSPort指向的Server,然后执行完毕后断开DBXConnection连接,释放TDSService。这也就解释了前面说的用TDSHTTPService来做负载和容错,可以靠DSHostname,DSPort来做的原因: TDSHTTPService只是剥离了HTTP的外衣,然后自己当客户端调用了服务罢了
没有评论:
发表评论