feat(im): 修 WebSocket 重复连接:connect 入口检测旧 socket 状态复用 / 重建,disconnect 解绑全部 handler

im
YunaiV 2026-05-21 08:41:44 +08:00
parent f7cda1fc4e
commit 8468d9bf4d
1 changed files with 23 additions and 1 deletions

View File

@ -138,6 +138,9 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
/**
* WebSocket
* yudao /infra/ws sendObject(type, content)
*
* / token `disconnect()` `connect()`
* token socket CONNECTING / OPEN token
*/
connect() {
// 鉴权用 refreshToken生命周期更长access token 过期后服务端会通过 frame 通知重登)
@ -146,6 +149,23 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
console.warn('[IM WS] refreshToken 为空,跳过连接')
return
}
// 旧 socket 还在 CONNECTING / OPEN 直接复用,避免叠加多份 onmessage 监听导致重复消息 / 提示音 / 已读上报
const existingSocket = this.socket
if (
existingSocket &&
(existingSocket.readyState === WebSocket.OPEN ||
existingSocket.readyState === WebSocket.CONNECTING)
) {
return
}
// 旧 socket 已 CLOSING / CLOSED解绑回调 + 清引用再 new避免老 handler 仍持有 store 引用阻碍 GC
if (existingSocket) {
existingSocket.onopen = null
existingSocket.onmessage = null
existingSocket.onerror = null
existingSocket.onclose = null
this.socket = null
}
const url = `${this.buildWsUrl()}/infra/ws?token=${refreshToken}`
this.socket = new WebSocket(url)
@ -752,7 +772,9 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
disconnect() {
if (this.socket) {
// close() 异步触发 onclose / onerror回调里会无条件 reconnect
// 主动关闭路径必须先解绑这两个 handler否则 3 秒后会自动连回去
// 主动关闭路径必须先全部解绑,否则 onclose 会引发自动重连CONNECTING 期间的 in-flight message 也可能被老 onmessage 投递到 stale 上下文
this.socket.onopen = null
this.socket.onmessage = null
this.socket.onclose = null
this.socket.onerror = null
this.socket.close()