From db2208cc92c4cc74278df804c6330f7be3d5ac7c Mon Sep 17 00:00:00 2001 From: ZhangAo Date: Mon, 13 Oct 2025 17:33:35 +0800 Subject: [PATCH] u --- .../src/stores/websocketStore.js | 88 ++++++++++++++++--- 1 file changed, 75 insertions(+), 13 deletions(-) diff --git a/code/link/link-frontend/src/stores/websocketStore.js b/code/link/link-frontend/src/stores/websocketStore.js index 3b39b4f4..173031b7 100644 --- a/code/link/link-frontend/src/stores/websocketStore.js +++ b/code/link/link-frontend/src/stores/websocketStore.js @@ -6,8 +6,19 @@ export function useWebSocket() { const isConnected = ref(false) const listeners = ref(new Set()) + // 定时器 + let pingInterval, pongTimeout, connectTimeout + + // 重连状态 let reconnecting = false let reconnectNotification = null + let reconnectDelay = 3000 + + // 常量 + const MAX_RECONNECT_DELAY = 30000 + const PING_INTERVAL = 5000 + const PONG_TIMEOUT = 10000 + const CONNECT_TIMEOUT = 3000 function connect(url) { if (isConnected.value) @@ -18,15 +29,20 @@ export function useWebSocket() { const ws = new WebSocket(url) socket.value = ws + // 连接超时 + connectTimeout = setTimeout(() => !isConnected.value && ws.close(), CONNECT_TIMEOUT) + ws.onopen = () => { + clearTimeout(connectTimeout) isConnected.value = true reconnecting = false - // 关闭重连提示 - if (reconnectNotification) { - reconnectNotification.close() - reconnectNotification = null - } - console.log('WebSocket 已连接') + reconnectDelay = 3000 + startHeartbeat() + + // 关闭重连通知 + reconnectNotification?.close() + reconnectNotification = null + ElNotification({ title: '成功', message: 'WebSocket 已连接', @@ -34,11 +50,14 @@ export function useWebSocket() { showClose: false, duration: 2000, }) + console.log('WebSocket 已连接') } ws.onmessage = (event) => { try { const message = JSON.parse(event.data) + if (message.type === 'PONG') + return resetPongTimeout() notifyListeners(message) } catch (err) { @@ -47,13 +66,22 @@ export function useWebSocket() { } } - ws.onclose = () => scheduleReconnect(url) - ws.onerror = () => scheduleReconnect(url) + ws.onclose = (event) => { + handleDisconnect() + if (event.code !== 1000) + scheduleReconnect(url) + } + + ws.onerror = (err) => { + console.error('WebSocket错误:', err) + handleDisconnect() + scheduleReconnect(url) + } } function disconnect() { socket.value?.close() - isConnected.value = false + cleanup() } function sendMessage(type, data) { @@ -71,9 +99,34 @@ export function useWebSocket() { listeners.value.forEach(cb => cb(message)) } + function startHeartbeat() { + pingInterval = setInterval(() => { + if (socket.value?.readyState === WebSocket.OPEN) { + sendMessage('PING') + pongTimeout = setTimeout(() => { + console.warn('未收到PONG,关闭WebSocket') + socket.value?.close() + }, PONG_TIMEOUT) + } + }, PING_INTERVAL) + } + + function resetPongTimeout() { + clearTimeout(pongTimeout) + } + + function handleDisconnect() { + isConnected.value = false + cleanup() + } + function scheduleReconnect(url) { - if (!reconnecting) { - reconnecting = true + if (reconnecting) + return + reconnecting = true + + // 显示一次重连提示 + if (!reconnectNotification) { reconnectNotification = ElNotification({ title: '提示', message: 'WebSocket 连接断开,正在重连...', @@ -82,10 +135,19 @@ export function useWebSocket() { duration: 0, }) } - console.log('WebSocket 即将重连...') + + console.log(`WebSocket将在${reconnectDelay / 1000}s后尝试重连`) setTimeout(() => { connect(url) - }, 3000) // 固定延迟重连,可按需改 + reconnectDelay = Math.min(reconnectDelay * 2, MAX_RECONNECT_DELAY) + reconnecting = false + }, reconnectDelay) + } + + function cleanup() { + clearInterval(pingInterval) + clearTimeout(pongTimeout) + clearTimeout(connectTimeout) } onScopeDispose(() => disconnect())