一直以来,delphi 的网络通讯层都是以indy 为主,虽然indy 的功能非常多,涉及到网络服务的
各个方面,但是对于大多数多层服务来说,就是需要一个快速、稳定、高效的传输层。Delphi 的 datasnap
主要通过三种实现数据通讯的,一种是大家恨得牙痒痒的indy,另外一种是通过iis 的isapi,最后一种是通过
apache 的动态模块(DSO) 来实现。
indy 的问题多多,大家基本上都是趋向使用后两种方式,后面两种方式的麻烦是必须安装IIS 或者是
Apache。用起来还要配置很多东西,也不是太方便。
还好,微软在Windows Vista (server 2008) 以后使用http.sys 作为web 服务的核心,IIS 也是通过这个核心
实现其web 服务的。使用http.sys 都有哪些优势呢?
1.不用做额外的编码,直接支持https(妈妈再也不用担心ios 10 要 https 了)
2.内核级的缓冲和内核级的请求队列(大大降低应用服务器自身的压力)
3.多个应用程序可以使用同一个端口(防火墙表示很欣慰)
4.内核级的SSL 支持
5.内核级的静态文件输出支持
6.理论上,这是windows 下最快的http 服务,没有之一。
这么多好处,那么我们是否可以在delphi 里面直接使用http.sys ,让delphi 的多层服务在windows 下飞起来?
答案是肯定的,delphi 完全可以非常顺利的使用http.sys 服务,不光是webbroke, datasanp, 包括我们常用的kbmmw.
目前delphi 的第三方控件里面支持http.sys 的主要有两个,一个是著名的控件商TMS, 其专门有一个控件叫TMS Sparkle,
主要就是封装http.sys 服务,这个公司的其他的一些多层控件都是架构在这个控件上的,唯一不好的是,,它是商业软件,需要
付费购买。另外一个就是著名的开源框架mormot。此作者的功力已经是恐龙级,可以进delphi 界牛人前十名。他在mormot
里面也封装了 http.sys. 由于是开源的,所以是需要自己把对应封装的代码拿出来,实现与delphi 现有的多层应用适配。
下面以mormot 封装的 THttpApiServer 为例,说明一下在多层应用中如何使用适配使用http.sys.
我们首先解决webbroker 中如何使用THttpApiServer?
其实如果大家对webbroker 比较了解的话,就知道webbroker 的工作原理就是把客户端来的请求分发到webbroker 的处理过程,
然后再把返回结果响应给客户端。那么我们需要做一个winapiWebBrokerBridge,功能就是完成以上要求。
首先下载mormot 源码,添加相关目录。
然后加入我们的单元,需要使用的相关对象声明如下:
unit winapiWebBrokerBridge; { by xalion 2016.12.25 } interface uses Classes, HTTPApp, SysUtils, system.NetEncoding, SynCommons, SynZip, SynCrtSock , WebBroker, WebReq; type EWBBException = class(EWebBrokerException); EWBBInvalidIdxGetDateVariable = class(EWBBException); EWBBInvalidIdxSetDateVariable = class(EWBBException ); EWBBInvalidIdxGetIntVariable = class(EWBBException ); EWBBInvalidIdxSetIntVariable = class(EWBBException ); EWBBInvalidIdxGetStrVariable = class(EWBBException); EWBBInvalidIdxSetStringVar = class(EWBBException); EWBBInvalidStringVar = class(EWBBException); Twinapirequestinfo=class(Tobject) protected FHttpServerRequest:THttpServerRequest; Finrawheaders:Tstringlist; FContentStream : TStream; FFreeContentStream : Boolean; Fhost:string; Fport:string; Fcontent:string; FURL:string; Fremoteip:string; Fcontentlength:integer; fInContentType:string; Fcommand:string; public constructor Create(C: THttpServerRequest); destructor Destroy; override; end; Twinapiresponseinfo=class(Tobject) protected FHttpServerRequest:THttpServerRequest; Foutrawheaders:Tstringlist; FContentStream : TStream; FFreeContentStream : Boolean; Fhost:string; Fport:string; Fcontent:string; Fcontenttype:string; Fcontentlength:integer; Fstatuscode:integer; FCookies: TCookieCollection; public constructor Create(C: THttpServerRequest); destructor Destroy; override; procedure AddCookiestohead; end; TwinapiAppRequest = class(TWebRequest) protected FRequestInfo : TwinapiRequestInfo; FResponseInfo : TwinapiResponseInfo; FFreeContentStream : Boolean; FStatusCode:integer; // function GetDateVariable(Index: Integer): TDateTime; override; function GetIntegerVariable(Index: Integer): Integer; override; function GetStringVariable(Index: Integer): string; override; function GetRemoteIP: string; override; function GetRawPathInfo:string; override; function GetRawContent: TBytes; override; public constructor Create(arequestinfo:Twinapirequestinfo; aresponseinfo:Twinapiresponseinfo); destructor Destroy; override; function GetFieldByName(const Name: string): string; override; function ReadClient(var Buffer; Count: Integer): Integer; override; function ReadString(Count: Integer):string; override; function TranslateURI(const URI: string): string; override; function WriteHeaders(StatusCode: Integer; const ReasonString, Headers: string): Boolean; override; end; TwinapiAppResponse = class(TWebResponse) protected FRequestInfo : TwinapiRequestInfo; FResponseInfo : TwinapiResponseInfo; function GetContent: string; override; function GetStatusCode: Integer; override; procedure SetContent(const AValue: string); override; procedure SetContentStream(AValue: TStream); override; procedure SetStatusCode(AValue: Integer); override; procedure SetStringVariable(Index: Integer; const Value:string); override; procedure SetDateVariable(Index: Integer; const Value: TDateTime); override; procedure SetIntegerVariable(Index: Integer; Value: Integer); override; public constructor Create(AHTTPRequest: TWebRequest;arequestinfo:Twinapirequestinfo; aresponseinfo:Twinapiresponseinfo); destructor Destroy; override; procedure SendRedirect(const URI: string); override; procedure SendResponse; override; procedure SendStream(AStream: TStream); override; function Sent: Boolean; override; end; TwinapiWebBrokerBridge = class(THttpApiServer) private // procedure RunWebModuleClass(C : THttpServerRequest); protected FWebModuleClass: TComponentClass; function Request(C : THttpServerRequest): cardinal;override; public procedure RegisterWebModuleClass(AClass: TComponentClass); end;
然后我们就可以使用这个,实现我们的webbroker 应用了。
我们使用delphi 自带的向导,开始建一个webserver.
点ok,继续
点完成。
生成对应的工程文件,然后我们替换主窗体的代码。
主程序对应的代码很简单。