unit HOHttpAsynPost;
interface
Uses System.Classes,Winapi.Windows,System.SysUtils,IHOHttpAsynPost
,uLogger,System.Net.URLClient, System.Net.HttpClient, System.Net.HttpClientComponent
,strUtils;
type TPostResProc = procedure(Buff:PWIdeChar;MsgID:PWIdeChar) of object;//定义回调
THONetHttp=class(TNetHTTPClient)
public
msgid:String;
PostRes:TPostResProc;
constructor Create(AOwner: TComponent); // override;
destructor Destroy; // override;
procedure RequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse);
procedure RequestError(const Sender: TObject; const AError: string);
end;
procedure HttpAsynPost(Url:widestring;Buff:Pwidechar;PostRes1:TPostResProc;Msgid1:widestring;ConnectionTimeout1: Integer;ResponseTimeout1: Integer); stdcall;
function GetDllPath: string;
implementation
procedure HttpAsynPost(Url:widestring;Buff:Pwidechar;PostRes1:TPostResProc;Msgid1:widestring;ConnectionTimeout1: Integer;ResponseTimeout1: Integer); stdcall;
var
Nhttp:THONetHttp;
Stream:TStringStream;
Buffer:Widestring;
function ChineseToUnicode(Inputstr: string): string;
var //Unicode编码
Wide_Str: WideString;
WideChar_Byte_Array: Array of Byte;
s2:string;
i:integer;
begin
Wide_Str := Inputstr;//转为Unicode
//字节数 = Unicode字数 * Unicode单字的字节数
SetLength(WideChar_Byte_Array, Length(Wide_Str) * sizeof(WideChar));
//复制到字节数组当中
Move(PChar(Wide_Str)^, WideChar_Byte_Array[0], Length(Wide_Str) * sizeof(WideChar));
i:=0;
while I<High(WideChar_Byte_Array) do
begin
if WideChar_Byte_Array[I+1]=0 then
S2:=S2+char(WideChar_Byte_Array[I])
else
S2:=S2+'\u'+inttohex(WideChar_Byte_Array[I+1])+inttohex(WideChar_Byte_Array[I]);
I:=I+2;
end;
result:=s2;
//释放字节数组
SetLength(WideChar_Byte_Array, 0);
WideChar_Byte_Array := Nil;
end;
Begin
try
Buffer:=Buff;
Buffer:=ChineseToUnicode(Buffer);
log.WriteLog('['+Msgid1+']'+Url+ #13#13+Buffer);
Stream:=TStringStream.Create;
Stream.WriteString( Buffer);
Stream.Position:=0;
Nhttp:=THONetHttp.Create(Nil);//每次调用启用一个新的THONetHttp with Nhttp do
begin
AcceptCharSet := 'utf-8';
AcceptEncoding := '65001';
AcceptLanguage := 'zh-CN';
ContentType := 'application/json'; //text/html
UserAgent := 'CNHIS URI Client/1.0';
Asynchronous:=True;
Nhttp.OnRequestCompleted:=RequestCompleted;
nhttp.OnRequestError:=RequestError;
ConnectionTimeout :=ConnectionTimeout1;
ResponseTimeout := ResponseTimeout1;
msgid:=Msgid1;//附加标记
PostRes:=PostRes1;//注册回调
Post(Url,Stream);
end;
EXcept
ON E:Exception do
Begin
log.WriteLog('['+Msgid1+']发送出错:' + e.Message );
End;
end;
end;
function GetDllPath: string;
var
ModuleName: string;
begin
SetLength(ModuleName, 255);
//取得Dll自身路径
GetModuleFileName(HInstance, PChar(ModuleName), Length(ModuleName));
Result := ExtractFileDir(PChar(ModuleName));
end;
{ TNetHttp }
constructor THONetHttp.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
end;
destructor THONetHttp.Destroy;
begin
inherited;
end;
procedure THONetHttp.RequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse);
Var
Buff:String;
Buffer:PwideChar;
Msgid1:PwideChar;
i:integer;
begin //异步返回
try
Msgid1:=@THONetHttp(sender).msgid[1];
Buff:=AResponse.ContentAsString(TEncoding.UTF8);
if Buff='' then
Buff:='[错误信息]服务器返回空';
Buffer:=@Buff[1];
log.WriteLog('['+Msgid1+']' +'API返回:'+Buffer);
if assigned(THONetHttp(sender).PostRes) then
Begin
THONetHttp(sender).PostRes(Buffer,Msgid1);//回调时带上MSGID实现调用方的唯一处理,含同步等待等接口不能返回对等唯一ID时的需求的实现
End;
THONetHttp(sender).Free;//释放
EXcept
ON E:Exception do
Begin
log.WriteLog('['+Msgid1+']'+'处理返回值出错:' + e.Message);
End;
end;
end;
procedure THONetHttp.RequestError(const Sender: TObject; const AError: string);
Var
Buff:String;
Buffer:PwideChar;
Msgid1:PwideChar;
i:integer;
begin
try
Msgid1:=@THONetHttp(sender).msgid[1];
Buff:='[错误信息]'+AError;
log.WriteLog('['+Msgid1+']'+Buff);
if assigned(THONetHttp(sender).PostRes) then
Begin
Buffer:=@Buff[1];
THONetHttp(sender).PostRes(Buffer,Msgid1);
End;
THONetHttp(sender).Free;
EXcept
ON E:Exception do
Begin
log.WriteLog('['+Msgid1+']'+'处理错误信息出错:' + e.Message);
End;
end;
end;
initialization
Log.SetLogDir(GetDllPath + '\..\Log\', 'Plugin.HttpAsynPost');
finalization
end.
function UnicodeToChinese(Inputstr: string): string;
var
I: Integer;
Index: Integer;
Temp, Top, Last: string;
begin//Unicode解码
index := 1;
while index >= 0 do
begin
index := Pos('\u', Inputstr) - 1;
if index < 0 then
begin
Last := Inputstr;
Result := Result + Last;
Exit;
end;
Top := Copy(Inputstr, 1, index); // 取出 编码字符前的 非 unic 编码的字符,如数字
Temp := Copy(Inputstr, index + 1, 6); // 取出编码,包括 \u,如\u4e3f
Delete(Temp, 1, 2);
Delete(Inputstr, 1, index + 6);
Result := Result + Top + WideChar(StrToInt('$' + Temp));
end;
end;
缺点:每次都新建,一定程度上浪费了系统资源,但是由于服务端返回并不可控,且调用进来后,每一个返回的处理也无法通过分析返回结果的方式实现,若哪位老师有更好的异步方案(几乎等同于要求同步处理,而实际同步了业务又不允许等待),请指点下,感谢!
|
请发表评论