Vue3中不能在setup里直接new WebSocket,因会导致多实例、内存泄漏、响应丢失;须用单例封装+显式生命周期管理+双向心跳检测+指数退避重连。
直接用 new websocket(url) 在 vue3 里跑不起来生产环境——连接断了不重连、心跳没响应就卡死、多个组件抢同一个 socket 实例,最后全乱套。
为什么不能在 setup 里直接 new WebSocket
Vue3 的响应式系统和组件生命周期对长连接很敏感。你在 setup 里每次调用 new WebSocket,都新建一个实例,但没人管它什么时候关、谁在用、断了怎么恢复。
- 组件卸载时
socket.onclose不触发,socket可能还在后台发心跳,造成内存泄漏 - 父子组件同时 connect,会建两个物理连接,服务端压力翻倍
-
onmessage回调里没法直接更新ref或reactive数据,容易丢响应
必须用单例 + 显式生命周期管理
所有组件共用一个连接实例,靠类的静态属性或模块顶层变量控制唯一性。关键不是“能不能”,而是“谁负责销毁”。
- 用
class WebSocketService封装,内部用private static instance: WebSocketService确保单例 - 导出的是实例(
export default new WebSocketService(url)),不是工厂函数 - 全局挂载时(如
app.config.globalProperties.$ws = wsService)要配合onUnmounted清理监听器,而不是关 socket - 真正关闭连接只应在应用退出或用户登出时手动调用
wsService.disconnect()
心跳检测必须双向 reset,不能只看 ping
只定时发 ping 不够。客户端发完 ping 后启动超时定时器,但只要收到来自服务端的任意消息(包括业务数据、pong、甚至未定义协议帧),都得立刻 clearTimeout 并重置计时器——否则网络抖动时会误判断连。
使用 `@ainative/vue-sdk` 为 Vue 3 应用添加 AI 聊天功能。适用于以下场景:(1) 安装 `@ainative/vue-sdk`,(2) 在 Vue 组件中使用 `useChat` 组合式函数,(3) 提供……
- 错误写法:
onmessage里只处理业务逻辑,忘了调用resetHeartbeatTimeout() - 正确做法:把
resetHeartbeatTimeout提成公共方法,在onmessage、onopen、onpong三处都调用 - 服务端返回的
pong必须是字符串"pong"或符合约定的 JSON,不能依赖event.data类型自动识别
重连策略要带退避(backoff),别狂刷
连续重连失败后,间隔时间必须指数增长,否则服务器日志会被 Connection refused 填满。
立即学习“前端免费学习笔记(深入)”;
- 初始重连间隔设为
1000ms,每失败一次 ×1.5,上限封顶到30000ms - 记录
reconnectAttempts,达到最大次数(如 5 次)后暂停自动重连,改由用户点击“重试”触发 -
onerror里不要直接重连——它可能只是某次 send 失败,不代表连接已断;应以onclose为准
最易被忽略的一点:WebSocket 连接状态不能只信 socket.readyState。它可能还是 OPEN,但中间代理早已静默丢包。必须靠心跳响应来判定真实可用性——这也是为什么「发 ping + 等 pong」和「收任意消息即续命」这两件事缺一不可。

















