|
|
/** * WebSocket 工具类 * * 功能说明: * 1. 封装WebSocket连接管理 * 2. 自动重连机制 * 3. 心跳检测 * 4. 订阅管理 * * 使用示例: * import WebSocketClient from '@/utils/websocket' * * // 连接
* WebSocketClient.connect('http://localhost:8080/ws/dashboard', () => { * console.log('连接成功') * // 订阅主题
* WebSocketClient.subscribe('/topic/dashboard/robot-picking', (data) => { * console.log('收到数据:', data) * }) * }) */
import SockJS from 'sockjs-client'import Stomp from 'stompjs'
class WebSocketClient { constructor() { this.stompClient = null this.connected = false this.reconnectAttempts = 0 this.maxReconnectAttempts = 3000 this.reconnectInterval = 10000 this.subscriptions = new Map() this.heartbeatInterval = null this.url = null this.onConnectedCallback = null }
/** * 连接WebSocket服务器 * * @param {string} url WebSocket服务器地址 * @param {function} onConnected 连接成功回调 * @param {function} onError 连接错误回调 */ connect(url, onConnected, onError) { this.url = url this.onConnectedCallback = onConnected
console.log('[WebSocket] 正在连接服务器...', url)
try { const socket = new SockJS(url) this.stompClient = Stomp.over(socket)
// 禁用调试日志(生产环境)
// 开发环境可以设置为 console.log
this.stompClient.debug = null
this.stompClient.connect( {}, frame => { console.log('[WebSocket] ✅ 连接成功') this.connected = true this.reconnectAttempts = 0 this.startHeartbeat()
if (onConnected) { onConnected(frame) } }, error => { console.error('[WebSocket] ❌ 连接失败:', error) this.connected = false this.handleDisconnect()
if (onError) { onError(error) } } ) } catch (error) { console.error('[WebSocket] 连接异常:', error) if (onError) { onError(error) } } }
/** * 订阅主题 * * @param {string} topic 主题名称 * @param {function} callback 消息回调函数 * @returns {string} 订阅ID */ subscribe(topic, callback) { if (!this.connected || !this.stompClient) { console.warn('[WebSocket] 未连接,无法订阅主题:', topic) return null }
console.log('[WebSocket] 订阅主题:', topic)
const subscription = this.stompClient.subscribe(topic, message => { try { const data = JSON.parse(message.body) callback(data) } catch (error) { console.error('[WebSocket] 解析消息失败:', error) } })
const subscriptionId = topic this.subscriptions.set(subscriptionId, subscription)
return subscriptionId }
/** * 取消订阅 * * @param {string} subscriptionId 订阅ID */ unsubscribe(subscriptionId) { const subscription = this.subscriptions.get(subscriptionId) if (subscription) { subscription.unsubscribe() this.subscriptions.delete(subscriptionId) console.log('[WebSocket] 取消订阅:', subscriptionId) } }
/** * 发送消息 * * @param {string} destination 目标地址 * @param {object} data 消息数据 */ send(destination, data) { if (!this.connected || !this.stompClient) { console.warn('[WebSocket] 未连接,无法发送消息') return }
this.stompClient.send(destination, {}, JSON.stringify(data)) }
/** * 断开连接 */ disconnect() { if (this.stompClient) { this.stompClient.disconnect(() => { console.log('[WebSocket] 已断开连接') }) this.connected = false this.stopHeartbeat() } }
/** * 处理断开连接 */ handleDisconnect() { this.connected = false this.stopHeartbeat()
// 自动重连
if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++ console.log(`[WebSocket] 尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`)
setTimeout(() => { if (this.url && this.onConnectedCallback) { this.connect(this.url, this.onConnectedCallback) } }, this.reconnectInterval) } else { console.error('[WebSocket] 达到最大重连次数,放弃重连') } }
/** * 启动心跳检测 */ startHeartbeat() { this.heartbeatInterval = setInterval(() => { if (this.connected && this.stompClient) { // 发送心跳消息
// 注意:如果后端没有心跳接口,可以注释掉这行
// this.send('/app/heartbeat', { timestamp: Date.now() })
} }, 30000) // 每30秒发送一次心跳
}
/** * 停止心跳检测 */ stopHeartbeat() { if (this.heartbeatInterval) { clearInterval(this.heartbeatInterval) this.heartbeatInterval = null } }
/** * 检查连接状态 * * @returns {boolean} 是否已连接 */ isConnected() { return this.connected }}
// 导出单例
export default new WebSocketClient()
|