使用http.sys,让delphi 的多层服务真的飞起来

原delphi窑洞洞主xalion在自己的博客上发过一篇文章:

《使用http.sys,让delphi 的多层服务飞起来》

http://www.cnblogs.com/xalion/p/6219515.html

这里边提到如何把mormot的httpserver抠出来,嫁接到webbroker上,非常好的思路。

可惜xalion没贴出全部源代码。

最近对WebBroker做了点深入研究,给出了c5soft的实现,贴出全部源代码。

目前是0.0.0.1版本,仅搭了个框架,但是明眼人一看就明白实现思路,一步一步可以把整个框架填满。

源代码在Delphi7 与Delphi 10.2下编译通过。

原代码在这里下载:https://wedelphi.com/t/419364/

框架的核心是 SynWebApp.pas,随后贴出。先看看SynBrokerTest.dpr

···

program SynBrokerTest;

{$APPTYPE CONSOLE}

uses

{$IFNDEF UNICODE}

FastMM4,

{$ENDIF}

WebBroker,

SynWebApp in ‘SynWebApp.pas‘,

uWebModule in ‘uWebModule.pas‘ {WebModule1: TWebModule};

{$R *.res}

begin

{$IFDEF UNICDOE}

ReportMemoryLeaksOnShutDown := True;

{$ENDIF}

Application.Initialize;

Application.CreateForm(TWebModule1, WebModule1);

Application.Run;

end.

···

下面是框架的核心文件SynWebApp.pas

···

{ *************************************************************************** }

{ mORMot HttpServer WebBroker Bridge }

{ by [email protected] Version 0.0.0.1 2018-5-20 }

{ *************************************************************************** }

{$DENYPACKAGEUNIT}

unit SynWebApp;

interface

uses Classes, SysUtils, WebBroker, HTTPApp, SynCommons, SynCrtSock;

const

//Request Header String

cstInHeaderMethod = 0; //string

cstInHeaderProtocolVersion = 1; //string

cstInHeaderURL = 2; //string

cstInHeaderQuery = 3; //string

cstInHeaderPathInfo = 4; //string

cstInHeaderPathTranslated = 5; //string

cstInHeaderCacheControl = 6; //string

cstInHeaderAccept = 8; //string

cstInHeaderFrom = 9; //string

cstInHeaderHost = 10; //string

cstInHeaderReferer = 12; //string

cstInHeaderUserAgent = 13; //string

cstInHeaderContentEncoding = 14; //string

cstInHeaderContentType = 15; //string

cstInHeaderContentVersion = 17; //string

cstInHeaderDerivedFrom = 18; //string

cstInHeaderTitle = 20; //string

cstInHeaderRemoteAddr = 21; //string

cstInHeaderRemoteHost = 22; //string

cstInHeaderScriptName = 23; //string

cstInHeaderContent = 25; //string

cstInHeaderConnection = 26; //string

cstInHeaderCookie = 27; //string

cstInHeaderAuthorization = 28; //string

//Request Header Integer

cstInHeaderContentLength = 16; //Integer

cstInHeaderServerPort = 24; //Integer

//Request Header DateTime

cstInHeaderDate = 7; //TDateTime

cstInHeaderIfModifiedSince = 11; //TDateTime

cstInHeaderExpires = 19; //TDateTime

//Response Header String

cstOutHeaderVersion = 0; //string

cstOutHeaderReasonString = 1; //string

cstOutHeaderServer = 2; //string

cstOutHeaderWWWAuthenticate = 3; //string

cstOutHeaderRealm = 4; //string

cstOutHeaderAllow = 5; //string

cstOutHeaderLocation = 6; //string

cstOutHeaderContentEncoding = 7; //string

cstOutHeaderContentType = 8; //string

cstOutHeaderContentVersion = 9; //string

cstOutHeaderDerivedFrom = 10; //string

cstOutHeaderTitle = 11; //string

//Response Header Integer

cstOutHeaderContentLength = 0; //Integer

//Response Header DateTime

cstOutHeaderDate = 0; //TDateTime

cstOutHeaderExpires = 1; //TDateTime

cstOutHeaderLastModified = 2; //TDateTime

type

TSynWebReqest = class(TWebRequest)

private

function GetHeader(const AUpKey: RawUTF8; const ASource: RawUTF8 = ‘‘; const Sep: AnsiChar = #13): RawUTF8;

protected

FContext: THttpServerRequest;

function GetStringVariable(Index: Integer): string; override;

function GetDateVariable(Index: Integer): TDateTime; override;

function GetIntegerVariable(Index: Integer): Integer; override;

function GetInternalPathInfo: string; override;

function GetInternalScriptName: string; override;

public

constructor Create(const AContext: THttpServerRequest);

// Read count bytes from client

function ReadClient(var Buffer; Count: Integer): Integer; override;

// Read count characters as a string from client

function ReadString(Count: Integer): string; override;

// Translate a relative URI to a local absolute path

function TranslateURI(const URI: string): string; override;

// Write count bytes back to client

function WriteClient(var Buffer; Count: Integer): Integer; override;

// Write string contents back to client

function WriteString(const AString: string): Boolean; override;

// Write HTTP header string

function WriteHeaders(StatusCode: Integer; const ReasonString, Headers: string): Boolean; override;

function GetFieldByName(const Name: string): string; override;

property Context: THttpServerRequest read FContext;

end;

TSynWebResponse = class(TWebResponse)

private

FStatusCode: Integer;

function GetContext: THttpServerRequest;

protected

function GetStringVariable(Index: Integer): string; override;

procedure SetStringVariable(Index: Integer; const Value: string); override;

function GetDateVariable(Index: Integer): TDateTime; override;

procedure SetDateVariable(Index: Integer; const Value: TDateTime); override;

function GetIntegerVariable(Index: Integer): Integer; override;

procedure SetIntegerVariable(Index: Integer; Value: Integer); override;

function GetContent: string; override;

procedure SetContent(const Value: string); override;

procedure SetContentStream(Value: TStream); override;

function GetStatusCode: Integer; override;

procedure SetStatusCode(Value: Integer); override;

function GetLogMessage: string; override;

procedure SetLogMessage(const Value: string); override;

public

procedure SendResponse; override;

procedure SendRedirect(const URI: string); override;

procedure SendStream(AStream: TStream); override;

property Context: THttpServerRequest read GetContext;

end;

TSynWebApplication = class(TWebApplication)

private

fRoot, fPort: SockString;

fServer: THttpApiServer;

function Process(FContext: THttpServerRequest): cardinal;

public

property Port: SockString read fPort;

constructor Create(AOwner: TComponent); override;

destructor Destroy; override;

procedure Run; override;

end;

implementation

uses Windows, BrkrConst, IniFiles, SynZip;

{ TSynWebApplication }

constructor TSynWebApplication.Create;

begin

inherited;

fRoot := ‘‘;

fPort := ‘8080‘;

fServer := THttpApiServer.Create(false);

fServer.AddUrl(fRoot, fPort, false, ‘+‘, true);

fServer.RegisterCompress(CompressDeflate); // our server will deflate html :)

fServer.OnRequest := Process;

fServer.Clone(31); // will use a thread pool of 32 threads in total

end;

destructor TSynWebApplication.Destroy;

begin

fServer.RemoveUrl(fRoot, fPort, False, ‘+‘);

fServer.Free;

inherited;

end;

procedure WaitForEscKey;

var

LInputRecord: TInputRecord;

LEvent: DWord;

LHandle: THandle;

begin

LHandle := GetStdHandle(STD_INPUT_HANDLE);

while True do begin

Win32Check(ReadConsoleInput(LHandle, LInputRecord, 1, LEvent));

if (LInputRecord.EventType = KEY_EVENT) and

LInputRecord.Event.KeyEvent.bKeyDown and

(LInputRecord.Event.KeyEvent.wVirtualKeyCode = VK_ESCAPE) then

break;

end;

end;

procedure TSynWebApplication.Run;

begin

WriteLn(‘Server Listening on http://localhost:‘+Port+‘ ...‘);

WriteLn(‘Press ESC to quit‘);

WaitForEscKey;

end;

function TSynWebApplication.Process(FContext: THttpServerRequest): cardinal;

var

HTTPRequest: TSynWebReqest;

HTTPResponse: TSynWebResponse;

begin

Result := 200;

try

HTTPRequest := TSynWebReqest.Create(FContext);

try

HTTPResponse := TSynWebResponse.Create(HTTPRequest);

HTTPResponse.StatusCode := 200;

try

HandleRequest(HTTPRequest, HTTPResponse);

Result := HTTPResponse.StatusCode;

finally

HTTPResponse.Free;

end;

finally

HTTPRequest.Free;

end;

except

//HandleServerException(ExceptObject, Output);

end;

end;

procedure InitApplication;

begin

Application := TSynWebApplication.Create(nil);

end;

{ TSynWebReqest }

function TSynWebReqest.GetHeader(const AUpKey: RawUTF8; const ASource: RawUTF8 = ‘‘; const Sep: AnsiChar = #13):

RawUTF8;

var

P, pUpKey, pSource: PUTF8Char;

cVal: RawUTF8;

begin

pUpKey := PUTF8Char(AUpKey);

if ASource = ‘‘ then

pSource := PUTF8Char(FContext.InHeaders)

else

pSource := PUTF8Char(ASource);

P := StrPosI(pUpKey, pSource);

if IdemPCharAndGetNextItem(P, pUpKey, cVal, Sep) then

Result := Trim(cVal)

else

Result := ‘‘;

end;

constructor TSynWebReqest.Create(const AContext: THttpServerRequest);

begin

FContext := AContext;

end;

function TSynWebReqest.GetDateVariable(Index: Integer): TDateTime;

begin

Result := Now;

end;

function TSynWebReqest.GetFieldByName(const Name: string): string;

begin

Result := ‘‘;

end;

function TSynWebReqest.GetIntegerVariable(Index: Integer): Integer;

begin

if Index = cstInHeaderContentLength then

Result := StrToIntDef(UTF8ToString(GetHeader(‘CONTENT-LENGTH‘)), 0)

else if Index = cstInHeaderServerPort then

Result := 80

else

Result := 0;

end;

function TSynWebReqest.GetInternalPathInfo: string;

begin

Result := ‘‘;

end;

function TSynWebReqest.GetInternalScriptName: string;

begin

Result := ‘‘;

end;

function TSynWebReqest.GetStringVariable(Index: Integer): string;

begin

if Index = cstInHeaderMethod then begin

Result := UTF8ToString(Context.Method);

end else if Index = cstInHeaderProtocolVersion then begin

Result := ‘‘;

end else if Index = cstInHeaderURL then begin

Result := UTF8ToString(Context.URL);

end else if Index = cstInHeaderQuery then begin

Result := ‘‘;

end else if Index = cstInHeaderPathInfo then begin

Result := ‘‘;

end else if Index = cstInHeaderPathTranslated then begin

Result := ‘‘;

end else if Index = cstInHeaderCacheControl then begin

Result := ‘‘;

end else if Index = cstInHeaderAccept then begin

Result := UTF8ToString(GetHeader(‘ACCEPT:‘));

end else if Index = cstInHeaderFrom then begin

Result := UTF8ToString(GetHeader(‘FROM:‘));

end else if Index = cstInHeaderHost then begin

Result := UTF8ToString(GetHeader(‘HOST:‘));

end else if Index = cstInHeaderReferer then begin

Result := UTF8ToString(GetHeader(‘REFERER:‘));

end else if Index = cstInHeaderUserAgent then begin

Result := UTF8ToString(GetHeader(‘USER-AGENT:‘));

end else if Index = cstInHeaderContentEncoding then begin

Result := UTF8ToString(GetHeader(‘CONTENT-ENCODING:‘));

end else if Index = cstInHeaderContentType then begin

Result := UTF8ToString(GetHeader(‘CONTENT-TYPE:‘));

end else if Index = cstInHeaderContentVersion then begin

Result := ‘‘;

end else if Index = cstInHeaderDerivedFrom then begin

Result := ‘‘;

end else if Index = cstInHeaderTitle then begin

Result := ‘‘;

end else if Index = cstInHeaderRemoteAddr then begin

Result := UTF8ToString(GetHeader(‘REMOTEIP:‘));

end else if Index = cstInHeaderRemoteHost then begin

Result := ‘‘;

end else if Index = cstInHeaderScriptName then begin

Result := ‘‘;

end else if Index = cstInHeaderContent then begin

Result := ‘‘;

end else if Index = cstInHeaderConnection then begin

Result := UTF8ToString(GetHeader(‘CONNECTION:‘));

end else if Index = cstInHeaderCookie then begin

Result := UTF8ToString(GetHeader(‘COOKIE:‘));

end else if Index = cstInHeaderAuthorization then begin

Result := ‘‘;

end;

end;

function TSynWebReqest.ReadClient(var Buffer; Count: Integer): Integer;

begin

Result := 0;

end;

function TSynWebReqest.ReadString(Count: Integer): string;

begin

Result := ‘‘;

end;

function TSynWebReqest.TranslateURI(const URI: string): string;

begin

Result := ‘‘;

end;

function TSynWebReqest.WriteClient(var Buffer; Count: Integer): Integer;

begin

Result := 0;

end;

function TSynWebReqest.WriteHeaders(StatusCode: Integer;

const ReasonString, Headers: string): Boolean;

begin

Result := False;

end;

function TSynWebReqest.WriteString(const AString: string): Boolean;

begin

Result := False;

end;

{ TSynWebResponse }

function TSynWebResponse.GetContent: string;

begin

Result := Context.InContent;

end;

function TSynWebResponse.GetContext: THttpServerRequest;

begin

Result := TSynWebReqest(FHTTPRequest).FContext;

end;

function TSynWebResponse.GetDateVariable(Index: Integer): TDateTime;

begin

Result := Now;

end;

function TSynWebResponse.GetIntegerVariable(Index: Integer): Integer;

begin

Result := 0;

end;

function TSynWebResponse.GetLogMessage: string;

begin

Result := ‘‘;

end;

function TSynWebResponse.GetStatusCode: Integer;

begin

Result := FStatusCode;

end;

function TSynWebResponse.GetStringVariable(Index: Integer): string;

begin

Result := ‘‘;

if Index = cstOutHeaderContentType then

Result := Utf8ToString(Context.OutContentType);

end;

procedure TSynWebResponse.SendRedirect(const URI: string);

begin

end;

procedure TSynWebResponse.SendResponse;

begin

end;

procedure TSynWebResponse.SendStream(AStream: TStream);

begin

end;

procedure TSynWebResponse.SetContent(const Value: string);

begin

Context.OutContent := StringToUTF8(Value);

end;

procedure TSynWebResponse.SetContentStream(Value: TStream);

begin

end;

procedure TSynWebResponse.SetDateVariable(Index: Integer;

const Value: TDateTime);

begin

end;

procedure TSynWebResponse.SetIntegerVariable(Index, Value: Integer);

begin

end;

procedure TSynWebResponse.SetLogMessage(const Value: string);

begin

end;

procedure TSynWebResponse.SetStatusCode(Value: Integer);

begin

FStatusCode := Value;

end;

procedure TSynWebResponse.SetStringVariable(Index: Integer;

const Value: string);

begin

if Index = cstOutHeaderContentType then

Context.OutContentType := StringToUTF8(Value);

end;

initialization

InitApplication;

end.

···

原文地址:https://www.cnblogs.com/c5soft/p/9064229.html

时间: 2024-10-19 23:28:18

使用http.sys,让delphi 的多层服务真的飞起来的相关文章

使用http.sys,让delphi的多层服务真的飞起来【第二部】

这是本专题的续集,没读过第一部的看这里:http://bbs.2ccc.com/topic.asp?topicid=548153 之所以要搞第二部是因为第一部跟贴太多,读起来不方便,浪费大家的时间. 今天咱们聊的主题是:Delphi的DataSnap实质分析先说DataSnap中文应该翻译成什么,我个人的译法是:数据快照.大家不要被这么多介绍DataSnap的资料弄晕了,其实原理非常简单.要把DataSnap搞明白,必须先把客户端的TClientDataset控件搞明白,不会,找度娘.下面简称C

使用http.sys,让delphi 的多层服务飞起来

一直以来,delphi 的网络通讯层都是以indy 为主,虽然indy 的功能非常多,涉及到网络服务的 各个方面,但是对于大多数多层服务来说,就是需要一个快速.稳定.高效的传输层.Delphi 的 datasnap 主要通过三种实现数据通讯的,一种是大家恨得牙痒痒的indy,另外一种是通过iis 的isapi,最后一种是通过 apache  的动态模块(DSO) 来实现. indy 的问题多多,大家基本上都是趋向使用后两种方式,后面两种方式的麻烦是必须安装IIS 或者是 Apache.用起来还要

使用delphi 开发多层应用(二十四)KbmMW 的消息方式和创建WIB节点

KbmMW 中支持基于UDP的消息广播,也支持TCP/IP hub/spoke 方式,还有 基于UDP或者TCP/IP 的点对点的消息传输. 1.基于UDP的消息广播 根据UDP  的工作原理,在同一个网段里面,可以发布广播包.这样发布者只需要发布一次, 消息就可以被同一网段上的所有订阅者收到.这样大大的降低了网络带宽.这个方式的最大缺点是 无法直接跨越网段,如果要跨越网段,就需要建立一个Gateway. Gateway 就是一个程序,连接两个网段. 它接受第一个网段的广播消息,然后再广播到第二

使用delphi 开发多层应用(二十三)KbmMW 的WIB

解释WIB 是什么之前,先回顾以下我们前面的各种服务工作方式.前面的各种服务的工作方式都是请求/应答方式. 客户端发送请求,服务器端根据客户端的请求,返回相应的结果.这种方式是一种顺序式访问,是一种紧耦合的方式. 服务器被动接受访问,服务器无法直接给客户端发消息.针对这种情况出现了发布/订阅方式.现在这种方式很热呀! 发布/订阅方式类似出版社发行杂志,出版社每年要求大家订阅杂志,当你订阅后,每月到时,不管你有没有问, 杂志都会准时送到你家门口.对于计算机系统类似,当你订阅了服务器上的某种消息后,

在Delphi开发的服务中调用指定应用程序

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://fxh7622.blog.51cto.com/63841/529033 在很多时候,我们需要使用服务启动指定的应用程序来做到隐蔽启动程序的目的. 但是当我们直接使用Winexec来运行的时候,你会发现系统提示出错.以下的代码就是如何在Delphi编写的服务中启动指定的应用程序. function RunProcess(const ProcessName: String): Boo

使用delphi 开发多层应用(十六)使用XMLRPC 实现basic4android 远程调用RTC服务(讲述了RTC的特点,其底层通讯协议是自己封装SOCK 库,与kbmmw 的适合场合不完全一样)

    RealThinClient (以下简称RTC) 也是一款delphi 多层开发的框架,由于其底层通讯协议是自己封装SOCK 库,抛弃了 大家诟病的indy,因此表现的非常稳定,效率也非常高,深受很多人的追捧.由于RTC 是从底层通讯做起的,因此通讯层的 功能非常强,但是在中间层数据库功能虽然有所实现,但是没有kbmmw 和RO 强,但是对于普通的远程调用做的非常优雅. 同时它重点在于使用http 协议实现功能调用,因此与kbmmw 的适合场合不完全一样. 由于RTC 可以非常快速的建立

使用delphi 开发多层应用(二十二)使用kbmMW 的认证管理器

从kbmmw 4.4 开始,增加了认证管理器,这个比原来的简单认证提供了更多的功能.细化了很多权限操作. 今天对这一块做个介绍. 要做一个认证管理,大概分为以下5步: 1.  定义你要保护的资源,一般是服务.函数,当然你只要不限麻烦,可以是任何东西: 2.  定义使用者(用户): 3.  定义角色,使用者通过角色与服务器打交道: 4.  定义角色或用户可以访问的资源(授权): 5. 定义认证与登录的限制(本步不是必须的). 一般来说,用户是通过配置文件或数据库来保存的,这样可以灵活的设置用户名与

Win7/Vista/Server2008下VS 环境 调试调用 HTTP.SYS 无法启动监听服务及启动后其他机器无法访问端口

一. VS调试在Win7(vista系列)操作系统下 HttpListener无法绑定多个 指定IP.端口问题 来自:http://www.cnblogs.com/ryhan/p/4195693.html 现象:System.Net.HttpListenerException (0x80004005): 拒绝访问. 原因:VS IDE 权限不够(生成的产物权限也会不够),提升UAC权限即可解决 步骤: 1.选中对应Project,右键添加->新增应用程序清单文件 app.manifest 2.将

转(Delphi 新窑洞):使用delphi 开发多层应用(十七)使用RTC web 服务器返回JSON

RTC作为delphi 的最专业的web 应用服务器,如果客户端要使用JSON 的话,那么使用RTC 应该也是一种 非常好的选择.下面我们做一个使用RTC web 服务器返回数据库JSON 的例子. 建立一个新的程序窗体,放置如图的控件: 其中server 的属性为 注意,这一块先不要选多线程,因为在这个简单的例子里面暂时不涉及到数据库池, 后面我会做数据库池的例子. RtcDataProvider1 的属性 然后设置好unidac 的数据库连接属性,我这里使用Firebird 作为数据库. 并