全栈视角下的实时通信:一次多设备在线问题的复盘
最近在做一个 IM 类的全栈项目,前端 React、后端 Go,实时通道走 WebSocket。功能跑通后,本地开发一切正常,一上生产环境就出怪事:用户同时开三四个标签页,只有前两个能加载出来,后面的页面一直转圈,刷新也没用。
现象与排查
第一反应是前端状态管理写错了,或者 WebSocket 重连逻辑有 bug。但奇怪的是,单个标签页完全正常,数量一多才出问题。后来用浏览器开发者工具抓网络,发现卡住的不是业务接口,而是连 WebSocket 握手都排不上队。
根因:被忽略的连接数限制
浏览器对同一个域的 HTTP/1.1 并发连接数有上限(常见是 6 个)。更要命的是,开发者工具开着的时候,它本身会占用一条持久连接。也就是说,留给业务的长连接名额比你想的更少。标签页一多,新的 WebSocket 握手就只能排队,于是页面卡在加载。
为什么本地 dev 不容易复现?因为 npm run dev 和 npm run preview 在连接复用、协议版本上的行为并不完全一致。很多只在生产环境暴露的问题,其实是被 dev 模式"掩盖"了。结论很朴素:上线前一定要用 preview 或真实部署环境复现一遍。
多设备在线状态怎么建模
另一个相关的问题是"在线状态"。简单的在线/离线已经不够用了,用户可能同时用 Web、桌面端、手机在线。正确的做法是:在 WebSocket 握手和心跳里带上 device 字段,服务端按 connection 维度聚合,而不是按用户维度粗暴地设一个在线标志。
这样多端才会互不踢下线,管理后台也能展示"Web / Desktop / iOS"这样的设备级图标,而不是一个笼统的绿点。
小结
实时通信的坑,往往不在协议本身,而在"浏览器约束 + 环境差异 + 状态建模"这三者的交界处。排查时先问自己三个问题:连接数够不够?dev 和生产一致吗?状态是按连接还是按用户聚合的?想清楚这三点,大部分多设备问题都能定位。
test1
文章作者
最近在做一个 IM 类的全栈项目,前端 React、后端 Go,实时通道走 WebSocket。功能跑通后,本地开发一切...
- 分类
- 技术
- 发布时间
- 2026-09-11
- 字数
- 约 832 字
- 阅读
- 8 次
