ASP.NET Core 5中SignalR的negotiate请求是否会导致503服务不可用错误?
问题根因分析
- 重连重试策略过于激进:你自定义的
reconnectFunc前100ms内重试间隔仅为50ms,单客户端单次重连失败每秒最多会触发20次negotiate请求,双Hub场景下就是40次/秒,和你观测到的每分钟50次的量级完全吻合。一旦出现网络波动、服务端短暂不可用的情况,大量客户端同时高频重试会直接打满IIS请求队列,触发503 Service Unavailable错误。 - loginHub缺少鉴权配置:如果你的loginHub接口开启了JWT鉴权,当前代码中loginHub初始化时没有配置
accessTokenFactory传递令牌,negotiate请求会直接返回401状态码,触发客户端自动重连逻辑,形成无限请求循环。 - IIS未开启WebSockets协议:如果站点没有启用WebSockets,SignalR会自动降级为长轮询、SSE等传输方式,这类传输方式会频繁发起negotiate请求维持连接,进一步放大请求量。
- 令牌过期触发循环重连:你配置的refreshToken间隔为24小时,如果JWT有效时长小于24小时,token过期后roomHub的请求会返回401,触发自动重连,也会产生大量无效negotiate请求。
修复方案
- 调整重连重试策略:把最低重试间隔调整到1000ms以上,避免短时间内高频重试引发的惊群效应,示例修改如下:
function reconnectFunc(retryContext) { // 首次重试至少间隔1秒 if (retryContext.elapsedMilliseconds < 10000) { return 1000; } // 后续按原有梯度拉长间隔即可 else if (retryContext.elapsedMilliseconds < 45000) { return 5 * 1000; } else if (retryContext.elapsedMilliseconds < 2 * 60 * 1000) { return 10 * 1000; } else if (retryContext.elapsedMilliseconds < 5 * 60 * 1000) { return 60 * 1000; } else if (retryContext.elapsedMilliseconds < 10 * 60 * 1000) { return 3 * 60 * 1000; } else if (retryContext.elapsedMilliseconds < 15 * 60 * 1000) { return 5 * 60 * 1000; } else { return 10 * 60 * 1000; } }
- 补全loginHub鉴权配置:如果loginHub需要鉴权,初始化时和roomHub一样添加
accessTokenFactory配置传递有效令牌。 - 开启IIS WebSockets功能:进入服务器管理器的「添加角色和功能」向导,在「Web服务器(IIS)- Web服务器 - 应用程序开发」中勾选「WebSocket协议」安装,安装后重启站点即可生效。
- 优化令牌刷新逻辑:把refreshToken的执行间隔调整为比JWT有效时长小10~15分钟,确保token过期前完成刷新,避免因令牌过期触发无效重连。
- 临时兜底限流:可以在IIS中给negotiate接口添加请求限流规则,避免短时间内异常请求量过高打垮服务。
内容的提问来源于stack exchange,提问作者beta
相关产品推荐
相关产品推荐

