You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 13:42:40