import { reactive, ref } from 'vue'; // WebSocket 工具类,封装了 WebSocket 的连接、发送、接收、心跳、重连和关闭等操作 class WebsocketUtil { // 构造函数,初始化 WebSocket 连接 constructor(url, time, params) { this.url = url; // WebSocket 服务器的 URL this.params = params; // WebSocket 连接参数 this.time = time; // 心跳发送的间隔时间(毫秒) this.socketTask = null; // WebSocket 任务对象 this.isOpen = false; // WebSocket 连接是否打开 // 定时器相关 this.reconnectTimeout = null; // 重连定时器 this.heartbeatInterval = null; // 心跳定时器 this.heartbeatTimeout = null; // 心跳超时定时器(检测 pong 响应) this.checkConnectionInterval = null; // 连接状态主动检查定时器 // 消息回调数组 this.messageCallbacks = []; // 存储外部注册的消息回调函数的数组 // 重连策略配置 this.reconnectAttempts = 0; // 当前重连次数 this.reconnectMaxAttempts = 5; // 最大重连次数(设为 Infinity 表示无限重试) this.reconnectDelay = 3000; // 基础重连延迟(毫秒) this.maxReconnectDelay = 30000; // 最大重连延迟(毫秒) // 初始化 WebSocket 连接 this.initializeWebSocket(); // 监听设备唤醒事件(浏览器环境) if (typeof document !== 'undefined') { document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible') { // 页面可见时,主动检查连接 this.checkConnection(); } }); } } // 初始化 WebSocket 连接 initializeWebSocket() { console.log('初始化WebSocket连接'); if (this.isOpen) { return; } this.socketTask = uni.connectSocket({ url: this.url, success: () => { console.log('WebSocket连接请求发送成功'); }, fail: (error) => { console.error('WebSocket连接失败', error); uni.$emit('is-socket-open', false); this.reconnect(); } }); // 连接打开事件 this.socketTask.onOpen((res) => { console.log('WebSocket连接正常!==', res); this.isOpen = true; // 重置重连状态 this.reconnectAttempts = 0; this.reconnectDelay = 3000; // 启动心跳和消息监听 this.startHeartbeat(); this.listenForMessages(); uni.$emit('is-socket-open', true); }); // 连接错误事件 this.socketTask.onError((res) => { console.log('WebSocket连接错误!==', res); uni.$emit('is-socket-open', false); this.reconnect(); }); // 连接关闭事件 this.socketTask.onClose((result) => { console.log('WebSocket连接已关闭', result); this.isOpen = false; this.reconnect(); }); // 启动连接状态主动检查(30秒一次) this.startConnectionCheck(); } // 启动心跳检测 startHeartbeat() { // 清除现有定时器 if (this.heartbeatInterval) clearInterval(this.heartbeatInterval); if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout); this.heartbeatInterval = setInterval(() => { if (this.isOpen) { // 发送心跳包 this.send(JSON.stringify({ "type": "ping_interval", "set": "pad" })); // 设置5秒超时:若未收到pong则重连 this.heartbeatTimeout = setTimeout(() => { console.log('心跳超时,主动断开并重连'); this.closeSocket(); this.reconnect(); }, 5000); } }, this.time); } // 启动连接状态主动检查(30秒一次) startConnectionCheck() { if (this.checkConnectionInterval) clearInterval(this.checkConnectionInterval); this.checkConnectionInterval = setInterval(() => { if (!this.isOpen && !this.reconnectTimeout) { console.log('主动检查到连接断开,触发重连'); this.reconnect(); } }, 30000); } // 发送消息 send(data, type) { if (this.socketTask && this.isOpen) { this.socketTask.send({ data: data, success: (res) => { // 发送成功,重置心跳(可选,根据业务需求) this.startHeartbeat(); }, fail: (error) => { console.error('消息发送失败', error); this.reconnect(); } }); } else { console.warn('WebSocket未连接,无法发送消息'); } } // 监听 WebSocket 消息 listenForMessages() { if (this.socketTask) { this.socketTask.onMessage((res) => { const data = res.data.toString(); try { // 尝试解析JSON,处理pong响应 const message = JSON.parse(data); if (message.type === 'pong') { // 收到pong,清除心跳超时 if (this.heartbeatTimeout) clearTimeout(this.heartbeatTimeout); } } catch (e) { console.warn('消息解析失败(非JSON格式):', e); } // 触发外部注册的回调函数 this.messageCallbacks.forEach(callback => callback(data)); }); } else { console.error('WebSocket 连接尚未建立,无法监听消息'); } } // 重连 WebSocket(指数退避策略) reconnect() { if (this.reconnectTimeout) clearTimeout(this.reconnectTimeout); // 达到最大重连次数,停止重试(可根据需求调整为无限重试) if (this.reconnectAttempts >= this.reconnectMaxAttempts) { console.log(`已达最大重连次数 ${this.reconnectMaxAttempts},停止重连`); return; } // 指数退避:延迟时间 = 基础延迟 * 2^重连次数,最大不超过maxReconnectDelay const delay = Math.min( this.reconnectDelay * Math.pow(2, this.reconnectAttempts), this.maxReconnectDelay ); this.reconnectTimeout = setTimeout(() => { this.reconnectAttempts++; console.log(`重连尝试 ${this.reconnectAttempts}/${this.reconnectMaxAttempts},延迟 ${delay}ms`); this.initializeWebSocket(); }, delay); } // 主动检查连接状态 checkConnection() { if (!this.isOpen && !this.reconnectTimeout) { this.reconnect(); } } // 关闭 WebSocket 连接 closeSocket() { if (this.socketTask) { uni.closeSocket({ success: () => { console.log('WebSocket连接已关闭'); this.isOpen = false; }, fail: (error) => { console.error('关闭WebSocket连接失败', error); } }); this.socketTask = null; } } // 外部注册消息回调函数 onMessage(callback) { this.messageCallbacks.push(callback); } // 外部注销消息回调函数 offMessage(callback) { // 若传入callback,则移除指定回调;否则清空所有回调 if (callback) { this.messageCallbacks = this.messageCallbacks.filter(cb => cb !== callback); } else { this.messageCallbacks = []; } } // 销毁 WebSocket 连接,清理资源 destroy() { this.closeSocket(); // 清除所有定时器 clearInterval(this.heartbeatInterval); clearTimeout(this.heartbeatTimeout); clearTimeout(this.reconnectTimeout); clearInterval(this.checkConnectionInterval); // 清空回调数组 this.messageCallbacks = []; console.log('WebSocket资源已销毁'); } } export default WebsocketUtil;