Delphi Http Https 最好的解决方法(二)

目录

1. 前言

2.功能代码

2.1. 接口单元 InterfaceDll.pas

2.2. 工具类 unt_objects.pas

2.3. 公共单元 uPub.pas

2.4. dll工程导出函数

2.5. 配置文件 set.ini

3. 结语


1. 前言

先看【Delphi Http Https 最好的解决方法(一)】再看这篇文章.

在 【Delphi Http Https 最好的解决方法(一)】,工具类定义了两个TIdHttp对象,一个用于http,另一个用于https请求。

后来我在其他项目中使用该接口的时候,遇到一个问题。

我上传1w条数据记录,我用这个接口来上传数据,碰巧这个请求耗时较长,一个请求要10秒左右,这个耗时太长了,我自己也看不下去了。所以, 【Delphi Http Https 最好的解决方法(一)】的生产使用环境有限,我就搞整了一个类似数据库连接池的工具类,在接口初始化的时候就能够创建多个TIdHttp对象,用于http和https,在上传模块,开启多个线程上传,测试时候开启了10个线程,每个线程处理1000个数据,算是达到要求了。

其实代码和【Delphi Http Https 最好的解决方法(一)】在一起的,在此我简单说明下,分享下。

2.功能代码

2.1. 接口单元 InterfaceDll.pas

unit InterfaceDll;

interface

uses
  unt_objects, Winapi.Windows, System.SysUtils, System.Classes, EncdDecd, Qjson;

var
  tool: TTools;
  pools: THttpConnectopnPool;

//----------------------------------测试部分------------------------------------
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//测试
function dll_test: Byte; stdcall;

//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//-------------------------普通 网络请求部分------------------------------------
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//初始化
function dll_init: Byte; stdcall;
//Post
function dll_post(sUrl, sJson, sHeader: PWideChar; var sOut: PWideChar): Byte; stdcall;
//Get
function dll_get(sUrl, sJson, sHeader: PWideChar; var sOut: PWideChar): Byte; stdcall;
//释放
function dll_uninit: Byte; stdcall;

//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//-----------------------连接池 网络请求部分------------------------------------
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//初始化
function dll_Pool_init: Byte; stdcall;
//Post
function dll_Pool_post(sUrl, sJson, sHeader: PWideChar; var sOut: PWideChar): Byte; stdcall;
//Get
function dll_Pool_get(sUrl, sJson, sHeader: PWideChar; var sOut: PWideChar): Byte; stdcall;
//释放
function dll_Pool_uninit: Byte; stdcall;

//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


implementation

uses uPub, uSuperObject, qaes;

//测试
function dll_test: Byte; stdcall;
begin
  Result:= 1;
end;

//-------------------------普通 网络请求部分------------------------------------
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//初始化
function dll_init: Byte;
begin
  Result:= 0;
  if not Assigned(tool) then
    tool:= TTools.Create;
  Result:= 1;
end;

/// <summary>
///   POST请求
/// </summary>
function dll_post(sUrl, sJson, sHeader: PWideChar; var sOut: PWideChar): Byte;
var
  json, jsArr: TQjson;
  I:integer;
  bHttps: Boolean;
begin
  Result:= 0;
  bHttps:= (Pos('https:', sUrl)>0);
  if Assigned(tool) then
  begin
    if tool._debug then
      systemLog('[dll_post]: '+ AnsiString(sJson));
    json:= TQJson.Create;
    try
      json.Parse(sHeader);
      tool._Https.Request.CustomHeaders.Clear;
      jsArr:= json.ItemByName('params');
      if jsArr<> nil then
      begin
        for I := 0 to jsArr.Count- 1 do
          tool._Https.Request.CustomHeaders.Values[jsArr.Items[I].ValueByName('key','')]:= jsArr.Items[I].ValueByName('value','')
      end;
    finally
      FreeAndNil(json);
    end;
    Result:= tool.SendPost(bHttps, sUrl, sJson, sOut);
  end
  else
  begin
    systemLog('[dll_post]: '+ Err_02);
    Exit;
  end;
end;

//Get
function dll_get(sUrl, sJson, sHeader: PWideChar; var sOut: PWideChar): Byte;
var
  json: ISuperObject;
  jsArr: TSuperArray;
  I:integer;
  bHttps: Boolean;
begin
  Result:= 0;
  sOut:= '';
  bHttps:= (Pos('https:', sUrl)>0);
  if Assigned(tool) then
  begin
    if tool._debug then
      systemLog('[dll_post]: '+ AnsiString(sJson));
    if sHeader<>'' then
      json:= SO(sHeader);
    if json<>nil then
    begin
      tool._Https.Request.CustomHeaders.Clear;
      jsArr:= json.O['headers'].AsArray;
      for I := 0 to jsArr.Length- 1 do
      begin
        if bHttps then
          tool._Https.Request.CustomHeaders.Values[jsArr.O[I].S['key']]:= jsArr.O[I].S['value']
        else
          tool._Https.Request.CustomHeaders.Values[jsArr.O[I].S['key']]:= jsArr.O[I].S['value'];
      end;
    end;
    Result:= tool.SendGet(bHttps, sUrl, sJson, sOut);
  end
  else
  begin
    systemLog('[dll_get]: '+ Err_02);
    Exit;
  end;
end;

//释放
function dll_uninit: Byte;
begin
  result:= 0;
  if Assigned(tool) then
    FreeAndNil(tool);
  result:= 1;
end;

//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

//-----------------------连接池 网络请求部分------------------------------------
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

//初始化
function dll_Pool_init: Byte; stdcall;
begin
  Result:= 0;
  if not Assigned(pools) then
    pools:= THttpConnectopnPool.Create(nil);
  Result:= 1;
end;

//Post
function dll_Pool_post(sUrl, sJson, sHeader: PWideChar; var sOut: PWideChar): Byte; stdcall;
var
  json, jsArr: TQjson;
  I:integer;
  bHttps: Boolean;
  conn: THttpConnection;
begin
  Result:= 0;
  bHttps:= (Pos('https:', sUrl)>0);
  if not Assigned(pools) then
  begin
    systemLog('[dll_post]: '+ Err_02);
    Exit;
  end;
  conn:= pools.getHttpConnection(bHttps);
  try
    json:= TQJson.Create;
    try
      json.Parse(sHeader);
      conn.Request.CustomHeaders.Clear;
      jsArr:= json.ItemByName('params');
      if jsArr<> nil then
      begin
        for I := 0 to jsArr.Count- 1 do
          conn.Request.CustomHeaders.Values[jsArr.Items[I].ValueByName('key','')]:= jsArr.Items[I].ValueByName('value','')
      end;
    finally
      FreeAndNil(json);
    end;
    Result:= conn.SendPost(bHttps, sUrl, sJson, sOut);
  finally
    pools.returnHttpConnection(bHttps, conn);
  end;
end;

//Get
function dll_Pool_get(sUrl, sJson, sHeader: PWideChar; var sOut: PWideChar): Byte; stdcall;
var
  json: ISuperObject;
  jsArr: TSuperArray;
  I:integer;
  bHttps: Boolean;
  conn: THttpConnection;
begin
  Result:= 0;
  sOut:= '';
  bHttps:= (Pos('https:', sUrl)>0);
  if not Assigned(pools) then
  begin
    systemLog('[dll_get]: '+ Err_02);
    Exit;
  end;

  conn:= pools.getHttpConnection(bHttps);
  try
    if sHeader<>'' then
      json:= SO(sHeader);
    if json<>nil then
    begin
      tool._Https.Request.CustomHeaders.Clear;
      jsArr:= json.O['headers'].AsArray;
      for I := 0 to jsArr.Length- 1 do
      begin
        if bHttps then
          tool._Https.Request.CustomHeaders.Values[jsArr.O[I].S['key']]:= jsArr.O[I].S['value']
        else
          tool._Https.Request.CustomHeaders.Values[jsArr.O[I].S['key']]:= jsArr.O[I].S['value'];
      end;
    end;
    Result:= conn.SendGet(bHttps, sUrl, sJson, sOut);
  finally
    pools.returnHttpConnection(bHttps, conn);
  end;
end;

//释放
function dll_Pool_uninit: Byte; stdcall;
begin
  Result:= 0;
  if Assigned(pools) then
    FreeAndNil(pools);
  Result:= 1;
end;

//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

end.

2.2. 工具类 unt_objects.pas

unit unt_objects;

interface

uses
  Winapi.Windows, Winapi.Messages, IdHTTP, IdSSLOpenSSL, System.SysUtils,
  System.Classes, System.IniFiles, System.StrUtils, System.Variants,
  Winapi.Security.Cryptography, Winapi.WinRT, Winapi.CommonTypes, System.Win.WinRT,
  Contnrs, Vcl.ExtCtrls, System.DateUtils;

const
  Err_02= '创建对象失败...';
  GFileName= 'set.ini';

type
  //普通Http请求
  TTools= class
  private
    FDebug    : Boolean;            //调试模式
    FHttp     : TIdHTTP;            //HTTP专用
    FHttps    : TIdHTTP;            //HTTPS专用
    FBusy     : Boolean;            //是否忙碌
    FIdSSL    : TIdSSLIOHandlerSocketOpenSSL;
    procedure DisConnect(bHttps: Boolean);
  published
    property _debug: Boolean read FDebug write FDebug;
    property _Https: TIdHTTP read FHttps write FHttps;
    property _Http: TIdHTTP read FHttp write FHttp;
    property _Busy: Boolean read FBusy write FBusy;
  public
    constructor Create();
    destructor Destroy; override;

    //发送Post请求
    function SendPost(bHttps: Boolean; sUrl, sJson: PWideChar; var sOut: PWideChar): Byte;
    //发送Get请求
    function SendGet(bHttps: Boolean; sUrl, sJson: PWideChar; var sOut: PWideChar): Byte;
  end;

  //Http Https连接池
  THttpConnection= class(TIdHTTP)
  public
    //发送Post请求
    function SendPost(bHttps: Boolean; sUrl, sJson: PWideChar; var sOut: PWideChar): Byte;
    //发送Get请求
    function SendGet(bHttps: Boolean; sUrl, sJson: PWideChar; var sOut: PWideChar): Byte;
  end;

  THttpConnectopnPool= class(TComponent)
  private
    fDefault: Integer;  //默认连接池数量
    fIdleSec: Integer;  //默认连接空闲时间(s)
    fReqSec:  Integer;  //默认请求超时时间(s)
    fHttpConnList: TComponentList;      //连接池对象容易
    fHttpsConnList: TComponentList;     //连接池对象容易
    fCleanTimer: TTimer;                //连接池定时器
    procedure fCleanTimerEvent(sender: TObject);  //定时器事件
    procedure fClean;             //清理空闲链接
    function fCreateHttpConnection(bHttps: Boolean= False): THttpConnection;  //创建新链接
  protected
    function getConnectionCount: Integer;  //获取连接池数量
    function getUnixTimeStampSecond: Integer;
  public
    constructor Create(owner: TComponent);
    destructor Destroy; override;

    property ConnctionCount: Integer read getConnectionCount;
    function getHttpConnection(bHttps: Boolean= false): THttpConnection;  //获取连接
    function returnHttpConnection(bHttps: Boolean; conn: THttpConnection): Boolean;       //归还连接
  end;

implementation

uses uPub;

{ TTools }

constructor TTools.Create;
var
  sIni: TIniFile;
begin
  FHttp  := Tidhttp.Create(nil);
  FHttp.HTTPOptions := [hoKeepOrigProtocol];          //关键参数, 关系到编码自动转换
  FHttp.HandleRedirects:= True;
  FHttp.ProtocolVersion:= pv1_1;
  FHttp.Request.Accept:= '*/*';
  FHttp.Request.ContentType:= 'application/json;charset=UTF-8';
  FHttp.Request.Connection:= 'close';
  FHttp.ReadTimeout:= 30* 1000;
  FHttp.ConnectTimeout:= 30* 1000;

  FHttps  := Tidhttp.Create(nil);
  FHttps.HTTPOptions := [hoKeepOrigProtocol];
  FHttps.HandleRedirects:= True;
  FHttps.ProtocolVersion:= pv1_1;
  FHttps.Request.Accept:= '*/*';
  FHttps.Request.ContentType:= 'application/json;charset=UTF-8';
  FHttps.Request.Connection:= 'close';
  FHttps.ReadTimeout:= 30* 1000;
  FHttps.ConnectTimeout:= 30* 1000;

  FIdSSL  := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  FIdSSL.SSLOptions.Method:= sslvSSLv23;
  FIdSSL.SSLOptions.Mode:= sslmClient;

  if FileExists(ExtractFilePath(Paramstr(0))+GFileName) then
  begin
    sIni:= TIniFile.Create(ExtractFilePath(Paramstr(0))+GFileName);
    try
      case sIni.ReadInteger('hq','sslver',1) of
        0: FIdSSL.SSLOptions.Method:= sslvSSLv2;
        1: FIdSSL.SSLOptions.Method:= sslvSSLv23;
        2: FIdSSL.SSLOptions.Method:= sslvSSLv3;
        3: FIdSSL.SSLOptions.Method:= sslvTLSv1;
        4: FIdSSL.SSLOptions.Method:= sslvTLSv1_1;
        5: FIdSSL.SSLOptions.Method:= sslvTLSv1_2;
      end;
    finally
      FreeAndNil(sIni);
    end;
  end;

  FHttps.IOHandler:= FIdSSL;
end;

destructor TTools.Destroy;
begin
  if Assigned(FHttps) then
    FreeAndNil(FHttps);
  if Assigned(FHttp) then
    FreeAndNil(FHttp);
  inherited;
end;

procedure TTools.DisConnect(bHttps: Boolean);
begin
  if bHttps then
  begin
    if FHttps.Connected then
      FHttps.Disconnect;
  end
  else
  begin
    if FHttp.Connected then
      FHttp.Disconnect;
  end;
end;

function TTools.SendGet(bHttps: Boolean; sUrl, sJson: PWideChar; var sOut: PWideChar): Byte;
var
  ResponseStream: TStringStream;
begin
  Result:= 0;
  sOut:= '';
  DisConnect(bHttps);
  ResponseStream:= TStringStream.Create('', TEncoding.UTF8);
  try
    try
      systemLog('Snd: '+ sJson);
      FHttps.Get(sUrl, ResponseStream);
      sOut:= PWideChar(UTF8Decode(AnsiToUtf8(ResponseStream.DataString)));
      systemLog('Rcv: '+ sOut);
      Result:= 1;
    except
      on e: Exception do
      begin
        systemLog('exp: '+ e.Message);
      end;
    end;
  finally
    DisConnect(bHttps);
  end;
end;

function TTools.SendPost(bHttps: Boolean; sUrl, sJson: PWideChar; var sOut: PWideChar): Byte;
var
  ResquestStream,ResponseStream : TStringStream;
begin
  Result:= 0;
  sOut:= '';
  DisConnect(bHttps);
  try
    systemLog('Snd: '+ sJson);
    ResquestStream := TStringStream.Create(UTF8Encode(sJson));
    ResponseStream := TStringStream.Create('', TEncoding.UTF8);
    //ResponseStream := TStringStream.Create('');
    try
      if bHttps then
        FHttps.Post(sUrl, ResquestStream, ResponseStream)
      else
        FHttp.Post(sUrl, ResquestStream, ResponseStream);
      sOut := PWideChar(UTF8Decode(AnsiToUtf8(ResponseStream.DataString)));
      //sOut := PWideChar(UTF8Decode(WideString(ResponseStream.DataString)));
      systemLog('Rcv: '+ sOut);
      Result:= 1;
    except
      on e: Exception do
        systemLog('Exp: '+ e.Message);
    end;
  finally
    DisConnect(bHttps);
  end;
end;

{ THttpConnection }

function THttpConnection.SendGet(bHttps: Boolean; sUrl, sJson: PWideChar;
  var sOut: PWideChar): Byte;
var
  ResponseStream: TStringStream;
begin
  Result:= 0;
  sOut:= '';
  DisConnect(bHttps);
  ResponseStream:= TStringStream.Create('', TEncoding.UTF8);
  try
    try
      systemLog('Snd: '+ sJson);
      Get(sUrl, ResponseStream);
      sOut:= PWideChar(UTF8Decode(AnsiToUtf8(ResponseStream.DataString)));
      systemLog('Rcv: '+ sOut);
      Result:= 1;
    except
      on e: Exception do
      begin
        systemLog('exp: '+ e.Message);
      end;
    end;
  finally
    DisConnect(bHttps);
  end;
end;

function THttpConnection.SendPost(bHttps: Boolean; sUrl, sJson: PWideChar;
  var sOut: PWideChar): Byte;
var
  ResquestStream,ResponseStream : TStringStream;
begin
  Result:= 0;
  sOut:= '';
  DisConnect(bHttps);
  try
    systemLog('Snd: '+ sJson);
    ResquestStream := TStringStream.Create(UTF8Encode(sJson));
    ResponseStream := TStringStream.Create('', TEncoding.UTF8);
    //ResponseStream := TStringStream.Create('');
    try
      if bHttps then
        Post(sUrl, ResquestStream, ResponseStream)
      else
        Post(sUrl, ResquestStream, ResponseStream);
      sOut := PWideChar(UTF8Decode(AnsiToUtf8(ResponseStream.DataString)));
      //sOut := PWideChar(UTF8Decode(WideString(ResponseStream.DataString)));
      systemLog('Rcv: '+ sOut);
      Result:= 1;
    except
      on e: Exception do
        systemLog('Exp: '+ e.Message);
    end;
  finally
    DisConnect(bHttps);
  end;
end;

{ THttpConnectopnPool }

constructor THttpConnectopnPool.Create(owner: TComponent);
begin
  inherited Create(owner);
  fDefault:= 20;
  fIdleSec:= 600;
  if not Assigned(fHttpConnList) then
    fHttpConnList:= TComponentList.Create;
  if not Assigned(fHttpsConnList) then
    fHttpsConnList:= TComponentList.Create;
  if (fCleanTimer= nil) then
  begin
    fCleanTimer:= TTimer.Create(Self);
    fCleanTimer.Name:= 'CleanTimer';
    fCleanTimer.Interval:= 10* 60* 1000;
    fCleanTimer.OnTimer:= fCleanTimerEvent;
    fCleanTimer.Enabled:= True;
  end;
end;

destructor THttpConnectopnPool.Destroy;
var
  index: Integer;
  http: TIdHttp;
begin
  for index := fHttpConnList.Count-1 downto 0 do
  begin
    http:= TIdHttp(fHttpConnList[index]);
    http.Disconnect;
    FreeAndNil(http);
  end;
  for index := fHttpsConnList.Count-1 downto 0 do
  begin
    http:= TIdHttp(fHttpsConnList[index]);
    http.Disconnect;
    FreeAndNil(http);
  end;
  inherited;
end;

procedure THttpConnectopnPool.fClean;
var
  index, iNow: Integer;
begin
  iNow:= getUnixTimeStampSecond;
  for index:= fHttpConnList.Count-1 downto 0 do
  begin
    if THttpConnection(fHttpConnList[index]).Tag>0 then //未使用得连接
    begin
      if fHttpConnList.Count> fDefault then
      begin
        if iNow-THttpConnection(fHttpConnList[index]).Tag> fIdleSec then
          fHttpConnList.Delete(index);
      end;
    end
    else
    begin
      if iNow+ THttpConnection(fHttpConnList[index]).Tag> fReqSec then
      begin
        fHttpConnList.Delete(index);
        if fHttpConnList.Count< fDefault then
          fHttpConnList.Add(fCreateHttpConnection);
      end;
    end;
  end;
  for index:= fHttpsConnList.Count-1 downto 0 do
  begin
    if THttpConnection(fHttpsConnList[index]).Tag>0 then //未使用得连接
    begin
      if fHttpsConnList.Count> fDefault then
      begin
        if iNow-THttpConnection(fHttpsConnList[index]).Tag> fIdleSec then
          fHttpsConnList.Delete(index);
      end;
    end
    else
    begin
      if iNow+ THttpConnection(fHttpsConnList[index]).Tag> fReqSec then
      begin
        fHttpsConnList.Delete(index);
        if fHttpsConnList.Count< fDefault then
          fHttpsConnList.Add(fCreateHttpConnection(True));
      end;
    end;
  end;
end;

procedure THttpConnectopnPool.fCleanTimerEvent(sender: TObject);
begin
  TTimer(sender).Enabled:= False;
  try
    try
      fClean;
    except
      on e: Exception do
        systemLog('[fCleanTimerEvent]: '+ e.Message);
    end;
  finally
    TTimer(sender).Enabled:= True;
  end;
end;

function THttpConnectopnPool.fCreateHttpConnection(bHttps: Boolean): THttpConnection;
var
  FHttp: THttpConnection;
  FIdSSL    : TIdSSLIOHandlerSocketOpenSSL;
  sIni: TIniFile;
begin
  Result:= nil;
  FHttp:= THttpConnection.Create(nil);
  FHttp.HTTPOptions := [hoKeepOrigProtocol];          //关键参数, 关系到编码自动转换
  FHttp.HandleRedirects:= True;
  FHttp.ProtocolVersion:= pv1_1;
  FHttp.Request.Accept:= '*/*';
  FHttp.Request.ContentType:= 'application/json;charset=UTF-8';
  FHttp.Request.Connection:= 'close';
  FHttp.ReadTimeout:= 60* 1000;
  FHttp.ConnectTimeout:= 60* 1000;

  if bHttps then
  begin
    FIdSSL  := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
    FIdSSL.SSLOptions.Method:= sslvSSLv23;
    FIdSSL.SSLOptions.Mode:= sslmClient;
    if FileExists(ExtractFilePath(Paramstr(0))+GFileName) then
    begin
      sIni:= TIniFile.Create(ExtractFilePath(Paramstr(0))+GFileName);
      try
        case sIni.ReadInteger('hq','sslver',1) of
          0: FIdSSL.SSLOptions.Method:= sslvSSLv2;
          1: FIdSSL.SSLOptions.Method:= sslvSSLv23;
          2: FIdSSL.SSLOptions.Method:= sslvSSLv3;
          3: FIdSSL.SSLOptions.Method:= sslvTLSv1;
          4: FIdSSL.SSLOptions.Method:= sslvTLSv1_1;
          5: FIdSSL.SSLOptions.Method:= sslvTLSv1_2;
        end;
      finally
        FreeAndNil(sIni);
      end;
    end;
    FHttp.IOHandler:= FIdSSL;
  end;
  Result:= FHttp;
end;

function THttpConnectopnPool.getConnectionCount: Integer;
begin
  //
end;

function THttpConnectopnPool.getHttpConnection(bHttps: Boolean): THttpConnection;
var
  index: Integer;
begin
  Result:= nil;
  if bHttps then
  begin
    for index := 0 to fHttpsConnList.Count- 1 do
    begin
      if THttpConnection(fHttpsConnList[index]).Tag>0 then
      begin
        Result:= THttpConnection(fHttpsConnList[index]);
        Result.Tag:= - getUnixTimeStampSecond;
      end;
    end;
    if Result= nil then
    begin
      Result:= fCreateHttpConnection(bHttps);
      Result.Tag:= - getUnixTimeStampSecond;
      fHttpsConnList.Add(Result);
    end;
  end
  else
  begin
    for index := 0 to fHttpConnList.Count- 1 do
    begin
      if THttpConnection(fHttpConnList[index]).Tag>0 then
      begin
        Result:= THttpConnection(fHttpConnList[index]);
        Result.Tag:= - getUnixTimeStampSecond;
      end;
    end;
    if Result= nil then
    begin
      Result:= fCreateHttpConnection(bHttps);
      Result.Tag:= - getUnixTimeStampSecond;
      fHttpConnList.Add(Result);
    end;
  end;
  if (Result<> nil) and (Result.Connected) then
    Result.Disconnect;
end;

function THttpConnectopnPool.getUnixTimeStampSecond: Integer;
begin
  Result:= DateTimeToUnix(Now)-8*60*60;
end;

function THttpConnectopnPool.returnHttpConnection(bHttps: Boolean; conn: THttpConnection): Boolean;
begin
  if bHttps then
    Result:= fHttpsConnList.IndexOf(conn)>-1
  else
    Result:= fHttpConnList.IndexOf(conn)>-1;
  if Result then
  begin
    if conn.Connected then
      conn.Disconnect;
    conn.Tag:= getUnixTimeStampSecond;
  end;
end;

end.

2.3. 公共单元 uPub.pas

unit uPub;

interface

uses
  System.SysUtils, System.Classes, qaes, qstring, IdHashMessageDigest, IdHash;

type
  TMD5= class(TIdHashMessageDigest5);

  TAppPara = class
  public
    class function AppPath: string;
    class function AppName: string;
  end;

  TFilePath = class(TAppPara)
  public
    class function IniFile: string;
  end;

//写日志
procedure systemLog(Msg: AnsiString);
//AES对象初始化
procedure InitEncrypt(sKey, sIv: PWideChar; aesModel, keyType, paddingmodel: integer; var AES: TQAES);
//字符串转MD5
function StrToMD5(sIn: WideString): WideString;

implementation

procedure systemLog(Msg: AnsiString);
var
  F: TextFile;
  FileName: string;
  ExeRoad: string;
begin
  try
    ExeRoad := ExtractFilePath(ParamStr(0));
    if ExeRoad[Length(ExeRoad)] = '\' then
      SetLength(ExeRoad, Length(ExeRoad) - 1);
    if not DirectoryExists(ExeRoad + 'log') then
    begin
      CreateDir(ExeRoad + '\log');
    end;
    FileName := ExeRoad + '\log\DLL_Log' + FormatDateTime('YYMMDD', NOW) + '.txt';
    if not FileExists(FileName) then
    begin
      AssignFile(F, FileName);
      ReWrite(F);
    end
    else
      AssignFile(F, FileName);
    Append(F);
    Writeln(F, FormatDateTime('HH:NN:SS.zzz ', Now) + Msg);
    CloseFile(F);
  except
    //可能在事务中调用,避免意外
    Exit;
  end;
end;

procedure InitEncrypt(sKey, sIv: PWideChar; aesModel, keyType, paddingmodel: integer; var AES: TQAES);
var
  AInitVector: TQAESBuffer;
  AKeyType: TQAESKeyType;
  I: Integer;
begin
  case keyType of
    0:
      AKeyType := kt128;
    1:
      AKeyType := kt192;
    2:
      AKeyType := kt256;
  end;
  if aesModel= 0 then
    AES.AsECB(sKey, AKeyType)
  else
  begin
    for I := 1 to Length(sIv) do
      AInitVector[I-1]:= byte(sIv[I-1]);
    AES.AsCBC(AInitVector, sKey, AKeyType);
  end;
  //AES.PaddingMode在AES.AsECB  AES.AsCBC中是默认值的 所以在以下进行单独设置
  case paddingmodel of
    0:
      AES.PaddingMode:= pmZero;
    1:
      AES.PaddingMode:= pmPKCS5;
    2:
      AES.PaddingMode:= pmPKCS7;
  end;
end;

//字符串转MD5
function StrToMD5(sIn: WideString): WideString;
var
  Md5Encode: TMD5;
begin
  Md5Encode:= TMD5.Create;
  result:= Md5Encode.HashToHex(Md5Encode.HashString(UTF8Encode(sIn)));
  Md5Encode.Free;
end;

{ TAppPara }

class function TAppPara.AppName: string;
begin
  Result := ExtractFileName(ParamStr(0));
end;

class function TAppPara.AppPath: string;
begin
  Result := ExtractFilePath(ParamStr(0));
end;

{ TFilePath }

class function TFilePath.IniFile: string;
begin
  Result := AppPath + 'set.ini';
end;

end.

2.4. dll工程导出函数

exports

  dll_init,
  dll_post,
  dll_get,
  dll_uninit,

  dll_pool_init,
  dll_pool_post,
  dll_pool_get,
  dll_pool_uninit;

2.5. 配置文件 set.ini

[hq]
sslver=1

---------------------------------------------------------------------------------------------------------------------------------

3. 结语

欢迎大家指教,该dll我用于不同项目中,请求正常。

如果生产环境上传单一,两种请求方式都可以,如果用到请求频繁,直接使用连接池方式。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: TStringList 是 Delphi 语言中的一种字符串列表类型。如果在 TStringList 中存储的中文字符出现乱码,则可以尝试以下方法解决这个问题: 1. 确保 TStringList 的编码格式与存储的中文字符的编码格式相同。可以使用 TStringList.DefaultEncoding 属性来设置编码格式。 2. 尝试使用不同的编码格式来存储中文字符。例如,可以使用 UTF-8 或 GB2312 编码格式来存储中文字符。 3. 如果 TStringList 用于读取文件,请确保文件的编码格式与 TStringList 的编码格式相同。可以使用 TStringList.LoadFromFile 方法的第个参数来指定文件的编码格式。 4. 如果 TStringList 用于写入文件,请确保文件的编码格式与 TStringList 的编码格式相同。可以使用 TStringList.SaveToFile 方法的第个参数来指定文件的编码格式。 5. 如果以上方法都无法解决乱码问题,可以尝试使用其他类型的字符串列表,例如 TEncodingStringList,它具有更强的编码处理能力。 示例代码: ``` uses System.Classes; procedure Test; var StringList: TStringList; begin StringList := TStringList.Create; try StringList.DefaultEncoding := TEncoding.UTF8; StringList.Add('中文'); StringList.SaveToFile('test ### 回答2: 在Delphi语言中,TStringList是用于存储文本字符串的类。中文乱码问题通常是由于编码不一致导致的,我们可以通过以下几种方法解决TStringList存储中文乱码的问题。 1. 设置正确的编码格式: 在存储中文字符串之前,可以通过设置TStringList的Encoding属性来指定正确的编码格式,例如: ``` StringList1.Encoding := TEncoding.UTF8; // 设置编码为UTF-8 ``` 这样在存储和读取中文字符串时,就会按照指定的编码格式进行处理,避免乱码问题的发生。 2. 使用Widestring类型: TStringList默认存储的是AnsiString类型,不适合存储包含中文字符的字符串。可以考虑改用Widestring类型,例如: ``` var StringList1: TStringList; Str: Widestring; begin StringList1 := TStringList.Create; Str := '中文字符串'; StringList1.Add(Str); // ... end; ``` 这样就可以正常存储和读取包含中文字符的字符串。 3. 显式指定编码转换: 如果存储和读取中文字符串的过程中遇到乱码问题,可以使用TEncoding类进行编码转换,例如: ``` var StringList1: TStringList; Str: AnsiString; NewStr: UnicodeString; begin StringList1 := TStringList.Create; Str := '中文字符串'; NewStr := TEncoding.Convert(TEncoding.Default, TEncoding.UTF8, Str); StringList1.Add(NewStr); // ... end; ``` 上述例子中,将AnsiString类型的Str转换为UnicodeString类型的NewStr,并按指定的编码格式进行存储。 通过以上这些解决方法,可以有效解决TStringList存储中文乱码的问题,确保中文字符串的正常存取和显示。 ### 回答3: Delphi的TStringList是一个用于管理字符串列表的类,但是其默认的字符编码是ANSI编码,而中文字符通常采用的是Unicode编码(UTF-8、UTF-16等)。因此,在使用TStringList存储中文字符时会出现乱码的问题。 解决此问题的方法是将TStringList的字符编码设置为与中文字符所使用的编码一致。首先,可以通过设置TStringList的Encoding属性实现。可以将其设置为UTF-8或UTF-16等Unicode编码格式,具体取决于应用程序的需求。例如,可以使用以下语句将TStringList的编码设置为UTF-8: TStringList1.Encoding := TEncoding.UTF8; 另外,也可以在加载或保存字符串列表内容时使用TFileStream或TStringStream来指定编码格式。通过使用指定的编码格式,可以确保TStringList正确地读取和显示中文字符。以下是一个示例: var StringList: TStringList; FileStream: TFileStream; begin StringList := TStringList.Create; try FileStream := TFileStream.Create('filename.txt', fmOpenRead); try StringList.LoadFromStream(FileStream, TEncoding.UTF8); // 处理字符串列表 finally FileStream.Free; end; finally StringList.Free; end; end; 在这个示例中,TStringList会从TFileStream中以UTF-8编码格式加载内容。使用相同的原理,可以使用TStringStream和其他适当的编码格式来保存和读取中文字符串。 通过这些方法,您可以正确地存储和处理中文字符,避免TStringList存储中文乱码的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值