Delphi中TRestRequest.Execute比TIdHttp.Post执行HTTPS请求慢的原因排查
环境与测试情况
- 服务器:Delphi VCL应用,基于
TIdHTTPWebBrokerBridge搭建,搭配配置了SSLOptions.CertFile/KeyFile/OnGetPassword的TIdServerIOHandlerSSLOpenSSL。WebModule中绑定到/some/path的WebActionItem.OnAction从数据库返回少量字符,整个处理耗时约50ms。 - 客户端1:Delphi测试VCL应用,使用
TRestClient+TRestRequest(请求方法为rmPost)访问https://localhost:NNNN/some/path。首次TRequest.Execute耗时超2000ms,后续请求耗时约1100ms。 - 客户端2:Delphi测试VCL应用,使用配置了
TIdSSLIOHandlerSocketOpenSSL的TIdHttp,执行TIdHttp.Post请求时,首次耗时略低于1000ms,后续仅约60ms。
注:服务器与两个客户端均在本地运行,返回结果均正确,且服务器端耗时不受客户端影响。
问题与疑问
- 为何会出现上述性能差异?
- 使用
TRestRequest时可能存在哪些使用错误? - Delphi
TRestClient是否有已知性能问题?
补充分析
- 编辑1:发现
TIdHttp.Post首次耗时与TRestRequest.Execute后续耗时接近,怀疑TRestRequest每次调用都会重建SSL IOHandler,导致无法复用缓存的性能优势。 - 编辑2:追踪到
TRESTRequest.Execute最终调用System.Net.HttpClient.Win.TWinHTTPClient.DoExecuteRequest(),耗时集中在winhttp.dll的WinHttpSendRequest()函数,推测这是Windows Server 2019(WinHttp.dll版本10.0.17763.4492)的系统级问题。
问题解答
1. 性能差异的核心原因
底层实现差异
TIdHttp基于Indy的OpenSSL封装,默认会复用SSL连接与会话缓存:首次请求完成后,连接会被保持(默认开启KeepAlive),SSL会话参数也会缓存,后续请求无需重新完成完整的SSL握手流程,因此后续请求耗时大幅降低。TRestClient在Windows平台下默认依赖winhttp.dll实现(TWinHTTPClient),其连接复用与SSL会话缓存的策略和Indy不同。从追踪结果看,WinHttpSendRequest()的高耗时,大概率是因为WinHTTP在Windows Server 2019的该版本中,对本地HTTPS请求的连接复用、SSL会话缓存存在优化缺陷,导致每次请求都需要重复执行大量SSL握手相关操作。
连接复用机制的区别
- Indy的
TIdHttp默认维护连接池,只要服务器支持Keep-Alive,就会复用已建立的TCP连接,避免每次重新握手。 TRestClient的连接复用行为受WinHTTP的配置和系统版本影响。在Windows Server 2019的特定版本中,WinHTTP可能对本地HTTPS连接的复用逻辑存在问题,导致即使开启了Keep-Alive,也无法有效复用连接,每次请求都需要重新建立SSL连接。
2. TRestRequest可能的使用错误
- 未复用
TRestClient实例:如果每次请求都创建新的TRestClient/TRestRequest实例,会导致每次都重新初始化HTTP客户端、建立新连接,无法利用连接复用的优势。正确的做法是全局复用一个TRestClient实例,仅创建TRestRequest实例或复用同一个TRestRequest修改参数后执行。 - 未配置连接超时与Keep-Alive:检查
TRestClient的ConnectionTimeout、KeepAlive属性是否合理配置。如果KeepAlive未开启,会强制每次请求关闭连接,导致后续请求重新建立连接。 - SSL配置缺失:虽然请求能成功,但如果
TRestClient的SSL配置未正确设置(如未指定证书验证策略),可能导致WinHTTP在每次请求时重复执行证书校验流程,增加耗时。
3. Delphi TRestClient的已知性能问题
- 跨平台实现不一致:Windows平台依赖
winhttp.dll,Linux/macOS依赖其他底层库,不同平台的性能表现差异较大。 - WinHTTP版本相关问题:在Windows Server 2019的部分版本中,WinHTTP对HTTPS请求的SSL会话缓存、连接复用存在已知的性能瓶颈,尤其是本地环回请求的场景。
- 连接池管理不足:
TRestClient的连接池默认配置可能不够灵活,无法像Indy那样精细控制连接复用的生命周期,导致高并发或频繁请求场景下性能下降。
验证与优化建议
- 复用
TRestClient实例:确保整个应用生命周期内复用同一个TRestClient,避免频繁创建销毁。 - 切换底层HTTP客户端:在Windows平台下,可将
TRestClient的ClientImplementation设置为ciIndy,改用Indy作为底层实现,复用Indy的高性能连接复用机制。 - 升级WinHTTP版本:尝试更新Windows Server 2019的系统补丁,升级
winhttp.dll到更高版本,修复已知的性能缺陷。 - 开启SSL会话缓存:对于
TRestClient,可通过配置WinHTTP的相关选项(如WINHTTP_OPTION_SESSION_CACHE_SIZE)来强制开启SSL会话缓存,减少握手耗时。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

