Delphi XE7+Indy TIdHTTP发起HTTPS请求遇Socket Error #10054问题排查
问题
我用Delphi XE7开发简单HTTPS请求功能时,遇到Socket Error #10054 Connection reset by peer错误,这个错误并非每次都会出现,30次请求里可能出现1-3次,也可能完全不出现。我已经替换了Indy最新的SSL DLL文件,但没有效果。以下是我的代码:
组件初始化代码
try IdSSLIOHandlerSocketOpenSSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(nil); with IdSSLIOHandlerSocketOpenSSL1 do begin //SSLOptions.Method := sslvTLSv1_1; //sslvSSLv23 SSLOptions.SSLVersions := [sslvSSLv2, sslvSSLv3, sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2]; SSLOptions.Mode := sslmClient; SSLOptions.VerifyMode := []; SSLOptions.VerifyDepth := 0; end; except on E: Exception do Showmessage(e.Message); end; try IdHTTP1 := TIdHTTP.Create(nil); with IdHTTP1 do begin IOHandler := IdSSLIOHandlerSocketOpenSSL1; AllowCookies := True; HandleRedirects := true; ProxyParams.BasicAuthentication := false; ProxyParams.ProxyPort := 0; Request.CharSet := 'utf-8'; Request.ContentType := 'application/json'; Request.Ranges.Units := 'bytes'; HTTPOptions := []; Intercept := IdLogEvent1; IOHandler.DefStringEncoding := enUTF8; end; //IdLogEvent1.Active := True; except on E: Exception do ShowMessage(e.Message); end;
请求循环代码
cnt := 0; repeat try if IdHTTP1 = nil then createIDHTTP; auth := ConvertToBase64('login1'+':'+'pass1'); IdHTTP1.Request.CustomHeaders.FoldLines := False; IdHTTP1.Request.CustomHeaders.Clear; IdHTTP1.ConnectTimeout := 10000; IdHTTP1.Request.CustomHeaders.Add('Authorization: Basic ' + auth); IdHTTP1.Request.CustomHeaders.Add('User-Agent: PostmanRuntime/7.29.2'); IdHTTP1.Request.CustomHeaders.Add('Accept: */*'); IdHTTP1.Request.CustomHeaders.Add('Accept-Encoding: gzip, deflate, br'); IdHTTP1.Request.CustomHeaders.Add('Connection: keep-alive'); res := IdHTTP1.Get('https://isms.center/api/sms/report?message_id=61'); memo2.Lines.Add(cnt.ToString() + ' ' + GetJSONValue(res, 'status')); Sleep(1000); except on E: Exception do begin memo2.Lines.Add(cnt.ToString() + ' ' + e.ClassName + ' error: ' + e.Message); end; end; DestroyIDHTTP; Inc(cnt); until cnt > 30;
分析与解决建议
1. 连接复用逻辑矛盾
你设置了Connection: keep-alive要求复用连接,但每次请求后都调用DestroyIDHTTP销毁组件,等于强制断开连接。服务器可能在组件销毁时仍在处理连接,从而触发重置错误。
- 解决:初始化一次
TIdHTTP和SSL Handler,循环复用组件,所有请求完成后再统一销毁。
2. SSL版本配置过于宽泛
你启用了从SSLv2到TLSv1.2的所有版本,其中SSLv2、SSLv3是已废弃的不安全协议,服务器可能对这类连接主动重置,或协议协商过程中出现兼容性问题。
- 解决:只启用高版本安全协议,比如:
或直接指定单一协议:SSLOptions.SSLVersions := [sslvTLSv1_2, sslvTLSv1_3];SSLOptions.Method := sslvTLSv1_2;
3. 冗余请求头引发异常
Request.Ranges.Units := 'bytes';:你是查询报表的GET请求,不需要设置范围请求头,多余配置可能导致服务器处理异常,建议移除。Accept-Encoding包含br(Brotli压缩):如果Indy的SSL Handler没有Brotli解压支持,会导致服务器返回压缩数据后处理失败,间接引发连接重置。可先去掉br,只保留gzip, deflate。
4. Indy组件配置遗漏
HTTPOptions := [];:清空了所有HTTP选项,其中hoKeepOrigProtocol等选项对连接稳定性有帮助,建议保留必要选项:HTTPOptions := [hoKeepOrigProtocol, hoForceEncodeParams];- 未设置
ReadTimeout:仅靠ConnectTimeout无法覆盖服务器响应慢的场景,建议添加IdHTTP1.ReadTimeout := 15000;
5. 异常后组件状态重置
请求抛出异常后,TIdHTTP内部状态可能异常,下次复用前需主动断开连接重置状态:
except on E: Exception do begin memo2.Lines.Add(cnt.ToString() + ' ' + e.ClassName + ' error: ' + e.Message); IdHTTP1.Disconnect; // 异常后主动断开,避免状态异常 end; end;
内容的提问来源于stack exchange,提问作者Aidyn
相关产品推荐
相关产品推荐

