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

.NET 6多异步任务共用HttpClient遇远程主机强制关闭连接问题

问题:多后台Worker共用HttpClient时出现连接被强制关闭错误

场景说明

使用.NET 6开发,应用通过多个后台Worker共用同一个HttpClient异步发起请求,偶尔会抛出连接被强制关闭的错误;但仅用单个Task执行时无此问题。

错误日志

System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..
 ---> System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host.
   --- End of inner exception stack trace ---
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource<System.Int32>.GetResult(Int16 token)
   at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](TIOAdapter adapter)
   at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory`1 buffer)
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)

已尝试的无效操作

设置ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12,问题未解决。

当前HttpClient配置

serviceCollection.AddHttpClient(Queries.Sne.Serpro.Api.Infracoes.InfracaoQuery.CLIENT_KEY, (provider, client) =>
{
    client.DefaultRequestHeaders.Add("Accept", "application/json");
    client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
    client.DefaultRequestHeaders.Add("Connection", "keep-alive");
    
    client.BaseAddress = new Uri("https://fake-link/");
});

解决方案

  • 移除手动添加的Connection: keep-alive请求头:HttpClient默认已启用连接池和长连接机制,手动设置该头会干扰.NET对连接的自动管理,容易引发服务器端连接冲突。
  • 调整HttpClient连接池参数:通过SocketsHttpHandler配置连接池的最大并发连接数、空闲连接超时等,匹配服务器端的连接限制:
serviceCollection.AddHttpClient(Queries.Sne.Serpro.Api.Infracoes.InfracaoQuery.CLIENT_KEY, (provider, client) =>
{
    client.DefaultRequestHeaders.Add("Accept", "application/json");
    client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
    client.BaseAddress = new Uri("https://fake-link/");
}).ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
{
    MaxConnectionsPerServer = 100, // 根据实际并发需求调整
    PooledConnectionIdleTimeout = TimeSpan.FromMinutes(5), // 建议与服务器的长连接超时保持一致
    PooledConnectionLifetime = TimeSpan.FromMinutes(10) // 定期回收旧连接,避免因服务器端连接过期引发错误
});
  • 添加请求重试策略:针对连接被强制关闭的异常,实现指数退避重试,可结合Polly库实现:
using Polly;
using Polly.Retry;

// 定义重试策略
AsyncRetryPolicy retryPolicy = Policy
    .Handle<HttpRequestException>()
    .Or<SocketException>(ex => ex.SocketErrorCode == System.Net.Sockets.SocketError.ConnectionReset)
    .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

// 将策略绑定到HttpClient
serviceCollection.AddHttpClient(Queries.Sne.Serpro.Api.Infracoes.InfracaoQuery.CLIENT_KEY, (provider, client) =>
{
    client.DefaultRequestHeaders.Add("Accept", "application/json");
    client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
    client.BaseAddress = new Uri("https://fake-link/");
}).AddPolicyHandler(retryPolicy);
  • 确认服务器端连接限制:部分服务器会对单个客户端的并发连接数、长连接时长做限制,多Worker并发时可能触发该限制,需联系服务端运维确认配置,或调整客户端的并发请求量。

内容的提问来源于stack exchange,提问作者Guilherme Bley

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 01:50:31