SignalR自动重连时服务端无法区分首次连接与重连请求
解决方案
方案一:客户端重连时添加自定义请求头
在客户端通过重连事件给重连请求添加专属标识头,服务端中间件通过该头识别重连请求:
客户端代码修改
this.hubConn = new HubConnectionBuilder() .withUrl("https://server/hubEndPoint", { skipNegotiation: true, transport: HttpTransportType.WebSockets }) .withAutomaticReconnect() .build(); // 监听重连开始事件,添加重连标识头 this.hubConn.onReconnecting((error) => { this.hubConn.options.headers['X-SignalR-Reconnect'] = 'true'; }); // 重连成功后重置请求头(可选) this.hubConn.onReconnected((connectionId) => { delete this.hubConn.options.headers['X-SignalR-Reconnect']; });
服务端中间件处理
在中间件中检查请求头X-SignalR-Reconnect,判断是否为重连请求:
public async Task InvokeAsync(HttpContext context, RequestDelegate next) { if (context.Request.Path.StartsWithSegments("/hubEndPoint") && context.Request.Method == HttpMethod.Get.Method) { bool isReconnect = context.Request.Headers.TryGetValue("X-SignalR-Reconnect", out var reconnectHeader) && reconnectHeader == "true"; if (isReconnect) { // 执行重连请求的处理逻辑 } else { // 执行首次连接请求的处理逻辑 } } await next(context); }
方案二:通过Connection-Id识别重连
SignalR自动重连时会尝试复用之前的Connection-Id,服务端可通过记录历史Connection-Id来判断是否为重连请求:
服务端逻辑
// 维护历史Connection-Id集合,需注意定期清理过期Id避免内存泄漏 private readonly HashSet<string> _historicalConnectionIds = new HashSet<string>(); public async Task InvokeAsync(HttpContext context, RequestDelegate next) { if (context.Request.Path.StartsWithSegments("/hubEndPoint") && context.Request.Method == HttpMethod.Get.Method) { if (context.Request.Headers.TryGetValue("Connection-Id", out var connectionId)) { bool isReconnect = _historicalConnectionIds.Contains(connectionId); if (isReconnect) { // 执行重连请求的处理逻辑 } else { // 首次连接,记录Connection-Id _historicalConnectionIds.Add(connectionId); // 执行首次连接请求的处理逻辑 } } } await next(context); }
注意:需在连接断开事件中移除对应Connection-Id,避免集合无限膨胀。
内容的提问来源于stack exchange,提问作者Dimitri
相关产品推荐
相关产品推荐

