jjw

写给自己的博客。 记录学习的点滴以备查。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

读DataSnap源代码(五)

Posted on 2015-09-18 13:19  jjw  阅读(542)  评论(0编辑  收藏  举报
 1 function TDSHTTPWebDispatcher.DispatchRequest(Sender: TObject;
 2   Request: TWebRequest; Response: TWebResponse): Boolean;
 3 begin
 4   try
 5     if Owner is TWebModule then
 6       DataSnapWebModule := TWebModule(Owner);
 7     try
 8       try
 9         RequiresServer;
10         TDSHTTPServerWebBroker(Self.FHttpServer).DispatchDataSnap(Request, Response);
11         Result := True;
12       except
13         on E: Exception do
14         begin
15           { Default to 500, like web services. }
16           Response.StatusCode := 500;
17           Result := True;
18         end;
19       end;
20     except
21       { Swallow any unexpected exception, it will bring down some web servers }
22       Result := False;
23     end;
24   finally
25     { Reset current DataSnapWebModule }
26     DataSnapWebModule := nil;
27   end;
28 end;

第10行代码中,请求被分配到TDSHTTPServerWebBorker中处理了。

 1 procedure TDSHTTPServerWebBroker.DispatchDataSnap(ARequest: TWebRequest;
 2   AResponse: TWebResponse);
 3 var
 4   LDispatch: TDSHTTPDispatch;
 5   LContext: TDSHTTPContextWebBroker;
 6 begin
 7   LDispatch := TDSHTTPApplication.Instance.HTTPDispatch;
 8   if LDispatch <> nil then
 9     DoCommand(LDispatch.Context, LDispatch.Request, LDispatch.Response)
10   else
11   begin
12     LContext := TDSHTTPContextWebBroker.Create(ARequest, AResponse);
13     try
14       DoCommand(LContext, LContext.FRequest, LContext.FResponse);
15     finally
16       LContext.Free;
17     end;
18   end;
19 end;

上面的第14行代码最终会转到TDSRESTServer类处理。

procedure TDSRESTServer.DoCommand(AContext: TDSHTTPContext; ARequestInfo: TDSHTTPRequest;
                                  AResponseInfo: TDSHTTPResponse);

 1 procedure TDSRESTServer.DoCommand(AContext: TDSHTTPContext; ARequestInfo: TDSHTTPRequest;
 2                                   AResponseInfo: TDSHTTPResponse);
 3 var
 4   Request: string;
 5   NextRequest: string;
 6   NextContext: string;
 7   RestCtxt: string;
 8   StartDispatch: Boolean;
 9 begin
10 
11   // HTTPDispatch object if necessary
12   StartDispatch := not TDSHTTPApplication.Instance.Dispatching;
13   if StartDispatch then
14     TDSHTTPApplication.Instance.StartDispatch(AContext, ARequestInfo, AResponseInfo);
15   try
16 {$IFNDEF POSIX}
17   if CoInitFlags = -1 then
18     CoInitializeEx(nil, COINIT_MULTITHREADED)
19   else
20     CoInitializeEx(nil, CoInitFlags);
21 {$ENDIF}
22   try
23     // check for context, if not found send the appropriate error message
24     Request := ARequestInfo.URI;
25     if Consume(FDSContext, Request, NextRequest) then
26     begin
27       Request := NextRequest;
28       if Consume(FRESTContext, Request, NextRequest) then
29       begin
30         // datasnap/rest
31         DoDSRESTCommand(ARequestInfo, AResponseInfo, NextRequest);
32       end
33       else if ConsumeOtherContext(Request, NextContext, NextRequest) then
34       begin
35         DoDSOtherCommand(AContext, ARequestInfo, AResponseInfo, NextContext, NextRequest, FDSServerName <> EmptyStr);
36       end
37       else
38       begin
39         RestCtxt := Trim(FRESTContext);
40         if RestCtxt = EmptyStr then
41           RestCtxt := SProtocolRestEmpty;
42 
43         AResponseInfo.ResponseNo := 501; {rest or other service not found in URI}
44         AResponseInfo.ContentText := Format(SProtocolNotSupported, [Request, RestCtxt]);
45         AResponseInfo.CloseConnection := true;
46       end;
47     end
48     else
49     begin
50       // This may dispatch .js files for example
51       DoCommandOtherContext(AContext, ARequestInfo, AResponseInfo, Request);
52     end;
53     if Assigned(Self.FTrace ) then
54     begin
55       FTrace(Self, AContext, ARequestInfo, AResponseInfo);
56     end;
57   finally
58                                                      
59     ClearInvocationMetadata();
60 {$IFNDEF POSIX}
61     CoUnInitialize;
62 {$ENDIF}
63   end;
64   finally
65     if StartDispatch then
66       TDSHTTPApplication.Instance.EndDispatch;
67   end;
68 end;


上面阴影的代码,一步一步的推进,先判断URI中是否包括Datasnap,再往判断是否包括REST,然后再继续处理。

到目前,代码已经从TWebModule到TDSHTTPWebDispatcher再到TDSRESTServer类中了。

而Delphi中,我们可以创建三种类型的DataSanp Server程序:

一是DataSanp REST App

二是DataSnap App

三是DataSnap WebBroker App

目前来看, Rest App和WebBroder App是很相似的。而 DataSanp App有些不同:

一是没有WebModule。

二是用 TDSHTTPService 代替了 TDSHTTPWebDispatcher。

三是Form1中代码简化了很多了,虽然project中也出现了  IdHTTPWebBrokerBridge,但也是不同的。(可以和rest app的比较)

 1 program Project1;
 2 
 3 uses
 4   Vcl.Forms,
 5   Web.WebReq,
 6   IdHTTPWebBrokerBridge,
 7   Unit1 in 'Unit1.pas' {Form1},
 8   ServerMethodsUnit1 in 'ServerMethodsUnit1.pas',
 9   ServerContainerUnit1 in 'ServerContainerUnit1.pas' {ServerContainer1: TDataModule};
10 
11 {$R *.res}
12 
13 begin
14   Application.Initialize;
15   Application.MainFormOnTaskbar := True;
16   Application.CreateForm(TForm1, Form1);
17   Application.CreateForm(TServerContainer1, ServerContainer1);
18   Application.Run;
19 end.


机制有何不同?