和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的外衣,然后自己当客户端调用了服务罢了