如何使用异步TNetHTTPClient?运行测试代码报错该如何解决?
报错原因
- 开启
Asynchronous := True异步模式后,Get方法会立即返回,不会等待网络请求执行完成,此时你拿到的IHTTPResponse对象还处于未就绪状态,直接访问ContentAsString属性就会触发句柄状态异常 - 你将
TNetHTTPClient声明为局部变量,Get调用后立刻在finally代码块中释放了实例,后台还在执行的异步请求失去了关联的宿主实例,也会导致状态错误
解决方法
分两种场景适配:
场景1:不需要异步逻辑,直接使用同步模式
把Asynchronous属性设为False即可,Get方法会阻塞直到请求完成后再返回,此时可以正常访问响应内容,代码示例:
procedure TForm1.Button1Click(Sender: TObject); var httpclient: TNetHTTPClient; output: string; begin httpclient := TNetHTTPClient.Create(nil); try httpclient.Asynchronous := False; output := httpclient.Get('https://google.com').ContentAsString; // 此处可正常处理返回结果 ShowMessage(output); finally httpclient.Free; end; end;
场景2:需要使用异步避免阻塞主线程
需要将TNetHTTPClient声明为类成员变量延长生命周期,通过OnRequestCompleted回调处理请求结果,实现代码如下:
首先在窗体类中声明成员和回调方法:
type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private FHttpClient: TNetHTTPClient; procedure RequestCompletedHandler(Sender: TObject; const AResponse: IHTTPResponse); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end;
对应实现部分:
constructor TForm1.Create(AOwner: TComponent); begin inherited; FHttpClient := TNetHTTPClient.Create(nil); FHttpClient.Asynchronous := True; // 绑定请求完成回调 FHttpClient.OnRequestCompleted := RequestCompletedHandler; end; destructor TForm1.Destroy; begin FHttpClient.Free; inherited; end; procedure TForm1.Button1Click(Sender: TObject); begin // 发起异步请求,不会阻塞主线程 FHttpClient.Get('https://google.com'); end; procedure TForm1.RequestCompletedHandler(Sender: TObject; const AResponse: IHTTPResponse); var output: string; begin if AResponse.StatusCode = 200 then begin output := AResponse.ContentAsString; // 回调运行在后台线程,更新UI需要同步到主线程 TThread.Synchronize(nil, procedure begin ShowMessage(output); end ); end; end;
注意事项
- 异步场景下不要提前销毁
TNetHTTPClient实例,必须保证请求执行期间实例有效 - 回调方法运行在后台线程,所有UI操作必须通过
TThread.Synchronize或TThread.Queue同步到主线程执行,否则会触发跨线程访问异常 - 可额外绑定
OnRequestError事件捕获异步请求过程中的网络异常
内容的提问来源于stack exchange,提问作者Blawjack
相关产品推荐
相关产品推荐

