首页 > 其他分享 >mormot2 THttpAsyncServer

mormot2 THttpAsyncServer

时间:2023-06-15 16:47:37浏览次数:39  
标签:begin end THttpAsyncServer req res mormot2 var Ctxt

mormot2 THttpAsyncServer

支持delphi和lazarus。

/// <author>cxg 2023-2-12</author>
/// mormot2 异步httpserver 支持delphi+lazarus
unit sock.mormot2.httpserver;
{$IFDEF fpc}
  {$MODE DELPHI}{$H+}
{$ENDIF}

interface

uses
  classes, keyValue.serialize, api.router, IniFiles,
  mormot.Net.sock, SysUtils, system.JSON, json.help, mormot.net.async,
  mormot.net.http, mormot.net.server;

var
  BinApis: TJSONObject;    //二进制API
  RestApis: TJSONObject;   //REST API,包括json,protobuf

const  //content-type
  cBin = 'application/octet-stream; charset=utf-8';
  cJson = 'application/json; charset=utf-8';
  cProtobuf = 'application/protobuf; charset=utf-8';

type
  THttpSVR = class
  private
    FServer: THttpAsyncServer;
    function process(Ctxt: THttpServerRequestAbstract): cardinal;
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

function ReadJsonFile(const FileName: string): string;
begin
  var f: TStringList := TStringList.Create;
  f.LoadFromFile(FileName, TEncoding.UTF8);
  Result := f.Text;
  f.Free;
end;

function strof(const aBytes: TBytes): RawByteString; overload;
begin
  SetLength(Result, Length(aBytes));
  Move(aBytes[0], Result[1], Length(aBytes));
end;

procedure setHeader(const Ctxt: THttpServerRequestAbstract; const ContentType: string);  //mormot2 binary http header
begin
  Ctxt.OutContentType := ContentType;
  Ctxt.OutCustomHeaders := 'Access-Control-Allow-Origin:*' + #13#10 + 'Access-Control-Allow-Methods:*' + #13#10 + 'Access-Control-Allow-Headers:*';
end;

procedure router(const Ctxt: THttpServerRequestAbstract);  //mormot2 router
begin
  if Pos('/bin', Ctxt.URL) > 0 then      //二进制 API
  begin
    setHeader(Ctxt, cBin);
    var req: TSerialize := tserialize.Create;
    var res: TSerialize := tserialize.Create;
    if Ctxt.InContent > '' then
      req.unMarshal(Ctxt.InContent);
    var url: string := Ctxt.URL;
    var arr: TArray<string> := url.Split(['/']);
    var funcName: string := arr[2];
    var ja: TJSONArray := BinApis.A['bin'];
    for var i: Integer := 0 to ja.Count - 1 do
    begin
      var o: TJSONObject := ja.Items[i] as TJSONObject;
      if o.S['funcname'] = funcName then
      begin
        RouterAPI(o.S['classname'], o.S['funcname'], [req, res]);
        Break;
      end;
    end;
    Ctxt.OutContent := res.marshal3;
    req.Free;
    res.Free;
  end
  else if Pos('/rest', Ctxt.URL) > 0 then    //JSON API
  begin
    setHeader(Ctxt, cJson);
    var url: string := Ctxt.URL;
    var arr: TArray<string> := url.Split(['/']);
    var resource: string := arr[2];
    var req: TSerialize := tserialize.Create;
    var res: TSerialize := tserialize.Create;
    req.asStr['url'] := url;
    if Ctxt.InContent > '' then
      req.asStr['body'] := Ctxt.InContent;
    req.asStr['type'] := 'json';
    var ja: TJSONArray := RestApis.A[resource];
    for var i: Integer := 0 to ja.Count - 1 do
    begin
      var o: TJSONObject := ja.Items[i] as TJSONObject;
      if o.S['method'] = Ctxt.Method then
      begin
        RouterAPI(o.S['classname'], o.S['funcname'], [req, res]);
        Break;
      end;
    end;
    Ctxt.OutContent := UTF8Encode(res.asStr['res']);
    req.Free;
    res.Free;
  end
  else if Pos('/protobuf', Ctxt.URL) > 0 then   //PROTOBUF API
  begin
    setHeader(Ctxt, cProtobuf);
    var url: string := Ctxt.URL;
    var arr: TArray<string> := url.Split(['/']);
    var resource: string := arr[2];
    var req: TSerialize := tserialize.Create;
    var res: TSerialize := tserialize.Create;
    req.asStr['url'] := url;
    if Ctxt.InContent > '' then
      req.asBytes['body'] := BytesOf(Ctxt.InContent);
    req.asStr['type'] := 'protobuf';
    var ja: TJSONArray := RestApis.A[resource];
    for var i: Integer := 0 to ja.Count - 1 do
    begin
      var o: TJSONObject := ja.Items[i] as TJSONObject;
      if o.S['method'] = Ctxt.Method then
      begin
        RouterAPI(o.S['classname'], o.S['funcname'], [req, res]);
        Break;
      end;
    end;
    Ctxt.OutContent := strof(res.asBytes['res']);
    req.Free;
    res.Free;
  end;
end;

{ THttpSVR }

constructor THttpSVR.Create;
var
  ini: tinifile;
  httpport: string;
  threadnum: integer;
  ssl: Boolean;
  KeepAliveTimeOut: Integer;
  queueLen: Integer;
  tls: TNetTlsContext;
begin
  ini := tinifile.create(extractfilepath(paramstr(0)) + 'server.conf');
  httpport := ini.readstring('config', 'httpport', '1122');
  threadnum := ini.readinteger('config', 'threadnum', 32);
  if threadnum > 256 then
    threadnum := 256;
  ssl := ini.ReadBool('config', 'ssl', False); //https?
  ini.free;
  KeepAliveTimeOut := 30000;
  if not ssl then
    FServer := THttpAsyncServer.Create(httpport, nil, nil, 'yn', threadnum, KeepAliveTimeOut, [])
  else
    FServer := THttpAsyncServer.Create(httpport, nil, nil, 'yn', threadnum, KeepAliveTimeOut, [hsoEnableTls]);
  queueLen := 100000;
  FServer.HttpQueueLength := queueLen;
  FServer.OnRequest := process;
  if not ssl then
    FServer.WaitStarted
  else
  begin
    InitNetTlsContextSelfSignedServer(tls);  //自签名
    try
      FServer.WaitStarted(10, @tls);
    finally
      DeleteFile(Utf8ToString(tls.CertificateFile));
      DeleteFile(Utf8ToString(tls.PrivateKeyFile));
    end;
  end;
  {$IFDEF console}
  Writeln('New THttpAsyncServer server');
  if not ssl then
    Writeln('Http port: ', httpport)
  else
    Writeln('Https port: ', httpport);
  Writeln('Thread num: ', threadnum);
  {$ENDIF}
end;

destructor THttpSVR.Destroy;
begin
  FreeAndNil(FServer);
  inherited;
end;

function THttpSVR.process(Ctxt: THttpServerRequestAbstract): cardinal;
begin
  router(Ctxt);
  Result := 200;
end;

initialization
  binapis := TJSONObject.Create;
  restapis := TJSONObject.Create;
  binapis.Parse(ReadJsonFile(ExtractFilePath(ParamStr(0)) + 'binrouter.json'));
  restapis.Parse(ReadJsonFile(ExtractFilePath(ParamStr(0)) + 'restrouter.json'));

finalization
  FreeAndNil(binapis);
  FreeAndNil(restapis);

end.

  

标签:begin,end,THttpAsyncServer,req,res,mormot2,var,Ctxt
From: https://www.cnblogs.com/hnxxcxg/p/17483302.html

相关文章

  • mormot2控件安装
    1.下载加入QQ群OneDelphi中间件开源群(群号:814696487)2.解压mormot23、把相关路径加到DelphiIDE......
  • mormot2控件安装
    1.下载加入QQ群OneDelphi中间件开源群(群号:814696487)2.解压mormot2;3.把相关路径加到DelphiIDE。......
  • mormot2客户端演示
    mormot2客户端演示   ......
  • mormot2事件驱动模型
    mormot2事件驱动模型异步套接字访问和事件循环是最佳服务器可伸缩性的关键。事件非常抽象,实际上只是每个连接上的基本R/W操作,与“tag”相关联。然后在这些基本的套接......
  • mormot2压力测试
    mormot2压力测试测试环境:inteli5-8400+8G内存+win115000个连接发出1千万次请求。   ......
  • mormot2 tls
    mormot2tlsmormot.net.sock.pasTNetTlsContext=record;典型用法withTHttpClientSocket.CreatedotryTLS.WithPeerInfo:=true;TLS.IgnoreCertificate......
  • mormot2.binary.serial.pas
    mormot2.binary.serial.pasunitmormot2.binary.serial;///<author>cxg2023-2-22</author>{$IFDEFfpc}{$MODEDELPHI}{$H+}{$ENDIF}interfaceusesmormot......
  • mormot2.json.serial
    unitmormot2.json.serial;///<author>cxg2023-2-11</author>{$IFDEFfpc}{$MODEDELPHI}{$H+}{$ENDIF}interfaceusesmormot.core.text,mormot.core.json......
  • mormot2 http路由
    mormot2http路由mormot.net.server.pas重写包括2部分:重写URL+重写HTTPMETHOD。如果你用过GO就会惊喜地发现它与GO的HTTP路由非常相似以及更加方便。///efficient......
  • mormot2中间件
    mormot2中间件中间件同一份pascal源码,同时支持在DELPHI和LAZARUS下面开发编译。 DELPHI编译目标平台WIN32,WIN64,LINUXINTEL64位CPU,主要是WINDOWS平台,因为DELPHI在W......