Blazor+SignalR每30秒触发TimeOutException错误日志问题咨询
我们用Blazor和SignalR搭建了客户端与服务器的WebSocket连接,现在所有系统都出现同一问题:每30秒控制台就会记录一条TimeoutException错误日志,内容如下:
This_console_error:7 fail:
Microsoft.AspNetCore.SignalR.Client.HubConnection[69]
HubConnection reconnecting due to an error. System.TimeoutException: Server timeout (30000.00ms) elapsed without receiving a message from the server.
_bound_js_globalThis_console_err
客户端的连接配置代码如下:
HubConnection hubConnection = new HubConnectionBuilder() .WithUrl(navigationManager.ToAbsoluteUri(HubConstants.TransportPackages), options => { options.AccessTokenProvider = () => Task.FromResult(authenticationService?.User?.Token); options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets | Microsoft.AspNetCore.Http.Connections.HttpTransportType.ServerSentEvents | Microsoft.AspNetCore.Http.Connections.HttpTransportType.LongPolling; }) .ConfigureLogging(logging => { logging.AddProvider(loggerProvider); }) .WithAutomaticReconnect() .Build(); hubConnection.On(HubConstants.ReceiveTransportPackage, handler); await hubConnection.StartAsync();
如果移除.WithAutomaticReconnect(),错误日志会变为:
fail: Microsoft.AspNetCore.SignalR.Client.HubConnection[12]
Connection is shutting down due to an error. System.TimeoutException: Server timeout (30000.00ms) elapsed without receiving a message from the server.
我们推测是超时设置(可能在服务器端)导致的,但疑惑为何要以错误级别记录?这是SignalR的设计特性,还是我们配置有误?我们知道移除logging.AddProvider(loggerProvider)能消除日志,但希望保留其他有用的日志信息。
1. 为什么超时会以错误级别记录?
这是SignalR客户端的设计特性。默认情况下,SignalR客户端的ServerTimeout为30秒,如果服务器端超过这个时间未发送任何消息(包括心跳包),客户端会判定连接异常中断,因此将该超时事件标记为错误级别日志——从客户端视角来看,这属于连接异常,符合错误日志的定义。
2. 解决办法
方案一:调整超时配置,确保心跳正常
可以同步调整客户端和服务器端的超时参数,或者让服务器定期发送心跳包,从根源上避免超时触发:
- 客户端修改超时:在
WithUrl的配置中延长ServerTimeout,比如设置为60秒:
options => { // 保留原有配置 options.ServerTimeout = TimeSpan.FromSeconds(60); }
- 服务器端配置心跳与超时:在Program.cs/Startup.cs中为SignalR Hub添加配置,确保心跳间隔小于客户端超时,且服务器的客户端超时比客户端设置略长:
services.AddSignalR(options => { options.KeepAliveInterval = TimeSpan.FromSeconds(30); // 每30秒发送一次心跳包 options.ClientTimeoutInterval = TimeSpan.FromSeconds(65); // 比客户端ServerTimeout多5秒,避免误判 });
方案二:过滤特定错误日志
如果不想调整超时,又想保留其他日志,可以在日志配置中过滤掉这两个特定的SignalR错误日志:
.ConfigureLogging(logging => { logging.AddProvider(loggerProvider); // 精准排除HubConnection的69和12号事件日志 logging.AddFilter((category, level, eventId) => { if (category == "Microsoft.AspNetCore.SignalR.Client.HubConnection" && (eventId.Id == 69 || eventId.Id == 12)) { return false; // 不记录这两个日志 } return true; // 其他日志正常记录 }); })
3. 自动重连的影响
启用.WithAutomaticReconnect()后,客户端超时会自动尝试重连,对应日志事件ID为69;禁用后,连接会直接关闭,事件ID为12——两者本质都是超时触发的错误,仅后续处理逻辑不同,因此日志级别均为错误。
内容的提问来源于stack exchange,提问作者Ben5

