Azure Web App上SignalR长轮询重复调用/negotiate偶发404排查
问题原因
- 15秒延迟核心是受影响客户端的网络出口代理/防火墙对SSE(Server-Sent Events)流式响应的默认缓冲策略导致:多数企业级安全代理会对
text/event-stream类型的响应设置15秒缓冲阈值,等待响应体达到最小体积才会转发给客户端,而SignalR SSE传输建立后服务端发送的初始握手帧体积很小,会被代理卡住15秒才转发到客户端。 - 服务端默认的SignalR握手超时时间恰好为15秒,等代理把响应转发到客户端时,服务端已经销毁了对应connectionId的连接上下文,所以客户端后续发送的握手请求会收到
Handshake was canceled错误,同connectionId的后续请求自然返回404。 - 连接销毁后客户端自动触发重连流程,就会重复调用
/negotiate接口,形成循环。 - 本地用Fiddler模拟无法复现,是因为Fiddler默认不会缓冲流式响应,直接实时转发数据,不会触发该问题。
无客户端访问权限的排查方案
- 调整SignalR传输优先级,优先降级到长轮询而非SSE:客户端初始化时在
withUrl配置中调整传输顺序,将LongPolling放到ServerSentEvents之前,或者直接对出现握手错误的客户端屏蔽SSE传输。你测试时强制长轮询运行正常,该调整可以直接解决现有异常用户的问题。 - 开启SignalR服务端详细日志:将
Microsoft.AspNetCore.SignalR和Microsoft.AspNetCore.Http.Connections日志级别调整为Debug,输出到Application Insights后匹配客户端上报的connectionId,核对服务端连接的创建、销毁时间点,确认是否为服务端主动超时关闭连接。 - 临时调整服务端握手超时时间验证根因:修改配置
services.AddSignalR(options => { options.HandshakeTimeout = TimeSpan.FromSeconds(30); }),如果调整后异常用户的报错消失,即可实锤是代理缓冲导致的超时问题。 - 新增客户端自动降级逻辑:在客户端
onclose回调中判断错误原因,如果是握手取消类错误,下次重连时直接指定使用长轮询传输,跳过SSE,避免循环报错。
内容的提问来源于stack exchange,提问作者M.E.
相关产品推荐
相关产品推荐

