.NET 6中HttpMessageInvoker连接超时未生效问题求助
问题描述
使用SocketsHttpHandler初始化HttpMessageInvoker,已将ConnectTimeout、KeepAlivePingTimeout、PooledConnectionIdleTimeout均设置为120秒,同时传入120秒超时的CancellationToken,调用SendAsync代码如下:
destinationResponse = await httpClient.SendAsync(destinationRequest, requestTimeoutToken);
HttpMessageInvoker创建代码:
var handler = new SocketsHttpHandler { UseProxy = false, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.None, UseCookies = false, EnableMultipleHttp2Connections = true, MaxConnectionsPerServer = 5000, }; handler.ConnectTimeout = TimeSpan.FromSeconds(120); handler.KeepAlivePingTimeout = TimeSpan.FromSeconds(120); handler.PooledConnectionIdleTimeout = TimeSpan.FromSeconds(120); return new HttpMessageInvoker(new ActivityPropagationHandler(handler), disposeHandler: true);
但访问不可达URL时,总是在21.2秒左右触发超时,而非预期的120秒。运行环境为Windows 11/Windows Server 2022,使用.NET 6.0版本。
解决方案
问题原因
21秒左右的超时是Windows系统TCP栈的默认重传总时长。Windows TCP默认会对未建立的连接进行多次重传,总耗时约21秒,这个行为会覆盖SocketsHttpHandler设置的ConnectTimeout,导致应用层超时设置不生效。
解决办法
方法一:修改系统TCP参数(需管理员权限)
通过调整注册表中的TCP配置,让系统尊重应用层的超时设置:
- 打开注册表编辑器,定位到路径:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters - 添加或修改以下DWORD值:
TcpInitialRtt:设置为120000(单位:毫秒,对应120秒),调整初始往返时间阈值TcpMaxRetransmissions:设置为0,禁用TCP栈的自动重传逻辑
- 重启系统使配置生效
方法二:自定义连接回调(代码层面解决)
通过重写SocketsHttpHandler的ConnectCallback属性,手动控制Socket连接超时,绕过系统TCP的默认重传:
var handler = new SocketsHttpHandler { UseProxy = false, AllowAutoRedirect = false, AutomaticDecompression = DecompressionMethods.None, UseCookies = false, EnableMultipleHttp2Connections = true, MaxConnectionsPerServer = 5000, // 自定义连接回调,手动控制超时 ConnectCallback = async (context, cancellationToken) => { using var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); socket.NoDelay = true; try { // 关联传入的取消令牌并设置120秒超时 using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); cts.CancelAfter(TimeSpan.FromSeconds(120)); await socket.ConnectAsync(context.DnsEndPoint, cts.Token); // 返回NetworkStream,让HttpHandler使用该连接 return new NetworkStream(socket, ownsSocket: true); } catch { socket.Dispose(); throw; } } }; handler.KeepAlivePingTimeout = TimeSpan.FromSeconds(120); handler.PooledConnectionIdleTimeout = TimeSpan.FromSeconds(120); return new HttpMessageInvoker(new ActivityPropagationHandler(handler), disposeHandler: true);
这种方式无需修改系统配置,直接在代码中控制连接超时逻辑,确保120秒超时生效。
内容的提问来源于stack exchange,提问作者A X
相关产品推荐
相关产品推荐

