如何从其他线程中止THTTPReqResp.Execute方法正在执行的HTTP请求
Delphi THTTPReqResp 主动中止HTTP请求解决方案
核心原理
THTTPReqResp底层基于WinINet API实现,本身没有暴露直接中止请求的方法,但可以通过主动关闭其内部使用的WinINet请求句柄,强制中断阻塞中的Execute调用。
实现步骤
- 引用
WinINet单元,用于调用WinINet原生API - 自定义工作线程类,增加私有变量存储WinINet请求句柄,并用临界区保护该句柄的多线程访问
- 绑定THTTPReqResp的
OnBeforePost事件,在事件触发时获取当前请求的WinINet句柄存入线程变量 - 需要中止线程时,先设置线程终止标志,再通过
InternetCloseHandle关闭存储的请求句柄,此时阻塞的Execute方法会抛出异常,即可中断执行流程
代码示例
uses System.SysUtils, System.Classes, System.SyncObjs, Soap.HTTPReqResp, WinINet; type TWorkThread = class(TThread) private FReqHandle: HINTERNET; FCritical: TCriticalSection; procedure OnBeforePost(const Sender: TObject; const Request: HINTERNET); protected procedure Execute; override; public constructor Create; destructor Destroy; override; procedure Stop; end; constructor TWorkThread.Create; begin inherited Create(True); // 创建挂起线程 FCritical := TCriticalSection.Create; FReqHandle := 0; end; destructor TWorkThread.Destroy; begin FCritical.Free; inherited; end; procedure TWorkThread.OnBeforePost(const Sender: TObject; const Request: HINTERNET); begin FCritical.Enter; try FReqHandle := Request; finally FCritical.Leave; end; end; procedure TWorkThread.Execute; var HTTPReqResp: THTTPReqResp; Request, Response: TStringStream; begin HTTPReqResp := nil; Request := nil; Response := nil; try HTTPReqResp := THTTPReqResp.Create(nil); HTTPReqResp.OnBeforePost := Self.OnBeforePost; // 绑定事件获取请求句柄 HTTPReqResp.URL := 'some_url'; HTTPReqResp.WebNodeOptions := [wnoSOAP12]; HTTPReqResp.SendTimeout := 60000; HTTPReqResp.ConnectTimeout := 60000; HTTPReqResp.ReceiveTimeout := 60000; Request := TStringStream.Create('<Request_XML>test</Request_XML>', TEncoding.UTF8); Response := TStringStream.Create('', TEncoding.UTF8); try HTTPReqResp.Execute(Request, Response); // 正常处理返回逻辑 except // 主动关闭句柄会触发异常,主动终止场景直接退出即可 on E: Exception do begin if Terminated then Exit; // 非主动终止的其他异常按原有业务逻辑处理 end; end; finally FCritical.Enter; try FReqHandle := 0; // 清空句柄标记 finally FCritical.Leave; end; Response.Free; Request.Free; HTTPReqResp.Free; end; end; procedure TWorkThread.Stop; begin Terminate; // 设置线程终止标志 FCritical.Enter; try if FReqHandle <> 0 then begin InternetCloseHandle(FReqHandle); // 关闭请求句柄,中断Execute调用 FReqHandle := 0; end; finally FCritical.Leave; end; WaitFor; // 等待线程安全退出 end;
注意事项
- 句柄访问必须加临界区保护,避免多线程下同时操作句柄导致的内存访问错误
- 主动关闭句柄触发的异常属于正常终止流程,无需当成业务错误处理
- 禁止直接在主线程释放正在执行请求的THTTPReqResp实例,必须先调用Stop方法终止请求流程再释放线程资源
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

