React集成SignalR时刷新客户端触发其他客户端send函数异常问题
React集成SignalR多客户端连接串扰问题排查
问题表现
- 多客户端登录接入SignalR的React应用后,任意客户端执行页面刷新操作,其余客户端会自动触发SignalR的send函数
- 客户端侧多窗口疑似共用同一个Socket连接,会互相触发对方的数据发送逻辑
现有代码参考
SignalR连接初始化代码
const connection = new signalr .HubConnectionBuilder() .withUrl(url, { skipNegotiation: true, transport: 1, }) .withHubProtocol(new signalRMsgPack.MessagePackHubProtocol()) .withAutomaticReconnect([]) .build();
异常触发的消息发送函数
function layoutPositionHandler(account) { let binaryAccount = msgpack.encode(account); ConnectionAlgo.send("PrePositions", binaryAccount); }
排查方向
- 连接实例作用域异常
检查connection实例是否被定义为模块全局变量、挂载到window对象,或是放在了跨窗口共享的状态容器中。如果连接实例没有和当前窗口、当前登录会话做唯一绑定,甚至被Service Worker、BroadcastChannel、localStorage事件做了跨窗口状态同步,就会出现单窗口操作触发多实例执行send的问题。另外注意React严格模式下,若连接初始化逻辑写在useEffect中但未配套返回清理函数(断开旧连接、解绑事件),会导致旧连接实例残留,触发非预期的回调执行。 - 服务端Hub消息路由逻辑错误
排查服务端对PrePositions消息的处理逻辑,大概率是某一客户端发消息后,服务端调用了Clients.All.SendAsync()这类全量广播方法,而非定向给调用方Clients.Caller或指定连接ID推送消息,导致其他客户端收到服务端推送的指令后,自动触发了绑定的layoutPositionHandler执行send。如果多窗口使用同一账号登录,还要检查是否配置了用户组广播,给用户组发消息时未过滤触发源连接,导致同账号下所有连接都收到触发指令。 - 前端全局事件绑定污染
检查layoutPositionHandler是否被绑定到了window全局事件、storage变更事件、页面可见性变化(visibilitychange)这类跨窗口可触发的事件上。页面刷新时会触发一系列全局生命周期事件,如果事件回调没有做当前窗口、当前激活连接的校验,就会出现一个窗口刷新,其他窗口监听到事件后自动执行发送逻辑。同时检查connection的消息接收监听(on方法绑定)是否存在重复绑定、未在组件卸载/连接断开时解绑的问题,残留的旧回调会在收到任意匹配消息时触发send。 - 传输层配置问题
现有配置开启了skipNegotiation: true且强制使用WebSocket传输(transport:1对应WebSocket传输模式),可临时关闭skipNegotiation走默认协商流程,排除跳过协商步骤导致服务端连接ID映射错误、多客户端请求被路由到同一连接上下文的问题。如果是本地开发环境,还要检查devServer的WebSocket代理配置是否存在连接复用错误,导致多标签页的请求被代理到同一个连接实例上。
内容的提问来源于stack exchange,提问作者celik
相关产品推荐
相关产品推荐

