/** * UniApp WebSocket封装类(局部使用版本) * 功能: * 1. 自动重连 * 2. 心跳检测 * 3. 消息发送队列 */ class WebSocketUtil { constructor(url, options = {}) { // WebSocket服务地址 this.url = url; // 配置选项 this.options = Object.assign( { // 心跳检测间隔(毫秒) heartbeatInterval: 30000, // 重连间隔(毫秒) reconnectInterval: 3000, // 最大重连次数,-1表示无限重连 maxReconnectAttempts: -1, // 心跳消息内容 heartbeatMessage: JSON.stringify({ to: 'heartbeat' }), // 消息回调函数 onMessage: null, // 连接打开回调 onOpen: null, // 连接关闭回调 onClose: null, // 连接错误回调 onError: null, // 重连回调 onReconnect: null }, options ); // 内部状态 this.socketTask = null; // WebSocket实例 this.isConnected = false; // 连接状态 this.isConnecting = false; // 是否正在连接中 this.reconnectAttempts = 0; // 重连尝试次数 this.heartbeatTimer = null; // 心跳定时器 this.reconnectTimer = null; // 重连定时器 this.messageQueue = []; // 消息队列 this.isManualClose = false; // 是否手动关闭 } /** * 建立WebSocket连接 */ connect() { if (this.isConnecting) return; this.isConnecting = true; this.socketTask = uni.connectSocket({ url: this.url, header: this.options.header || {}, protocols: this.options.protocols || [], success: () => { console.log('WebSocket连接创建成功'); }, fail: (error) => { console.error('WebSocket连接创建失败', error); this.reconnect(); }, complete: () => { this.isConnecting = false; } }); // 监听WebSocket连接打开事件 this.socketTask.onOpen((res) => { console.log('WebSocket连接已打开', res); this.isConnected = true; this.reconnectAttempts = 0; // 清除重连定时器 if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; } // 开始心跳检测 this.startHeartbeat(); // 发送队列中的消息 this.flushMessageQueue(); // 调用回调函数 if (typeof this.options.onOpen === 'function') { this.options.onOpen(res); } }); // 监听WebSocket接收到服务器的消息事件 this.socketTask.onMessage((res) => { // 调用回调函数 if (typeof this.options.onMessage === 'function') { this.options.onMessage(res); } }); // 监听WebSocket错误事件 this.socketTask.onError((error) => { console.error('WebSocket发生错误', error); this.isConnected = false; // 调用回调函数 if (typeof this.options.onError === 'function') { this.options.onError(error); } // 尝试重连 if (!this.isManualClose) { this.reconnect(); } }); // 监听WebSocket关闭事件 this.socketTask.onClose((res) => { console.log('WebSocket连接已关闭', res); this.isConnected = false; // 停止心跳检测 this.stopHeartbeat(); // 调用回调函数 if (typeof this.options.onClose === 'function') { this.options.onClose(res); } // 尝试重连 if (!this.isManualClose) { this.reconnect(); } }); } /** * 重新连接 */ reconnect() { // 如果是手动关闭或已达到最大重连次数,则不再重连 if ( this.isManualClose || (this.options.maxReconnectAttempts !== -1 && this.reconnectAttempts >= this.options.maxReconnectAttempts) ) { return; } // 清除之前的重连定时器 if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); } // 增加重连次数 this.reconnectAttempts++; console.log(`WebSocket尝试第${this.reconnectAttempts}次重连...`); // 设置重连定时器 this.reconnectTimer = setTimeout(() => { this.connect(); }, this.options.reconnectInterval); // 调用回调函数 if (typeof this.options.onReconnect === 'function') { this.options.onReconnect({ attempts: this.reconnectAttempts, maxAttempts: this.options.maxReconnectAttempts }); } } /** * 开始心跳检测 */ startHeartbeat() { // 清除之前的心跳定时器 this.stopHeartbeat(); // 设置新的心跳定时器,增加判断条件避免不必要的心跳 this.heartbeatTimer = setInterval(() => { if (this.isConnected && this.socketTask && this.socketTask.readyState === 1) { console.log('WebSocket发送心跳'); this.send(this.options.heartbeatMessage); } }, this.options.heartbeatInterval); } /** * 停止心跳检测 */ stopHeartbeat() { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); this.heartbeatTimer = null; } } /** * 发送消息 * @param {String|Object} data 消息内容 * @returns {Promise} 发送结果 */ send(data) { return new Promise((resolve, reject) => { // 如果消息是对象,则转为JSON字符串 if (typeof data === 'object') { data = JSON.stringify(data); } // 如果连接已打开,直接发送 if (this.isConnected && this.socketTask) { this.socketTask.send({ data, success: (res) => { console.log('WebSocket消息发送成功', data); resolve(res); }, fail: (error) => { console.error('WebSocket消息发送失败', error); reject(error); } }); } else { // 否则加入消息队列 console.log('WebSocket连接未打开,消息加入队列', data); this.messageQueue.push({ data, resolve, reject }); // 如果未连接,则尝试连接 if (!this.isConnected && !this.isConnecting) { this.connect(); } } }); } /** * 发送队列中的消息 */ flushMessageQueue() { if (this.messageQueue.length === 0) return; console.log(`WebSocket发送队列中的${this.messageQueue.length}条消息`); // 复制队列并清空原队列 const queue = [...this.messageQueue]; this.messageQueue = []; // 发送队列中的消息 queue.forEach(item => { this.socketTask.send({ data: item.data, success: (res) => { console.log('WebSocket队列消息发送成功', item.data); item.resolve(res); }, fail: (error) => { console.error('WebSocket队列消息发送失败', error); item.reject(error); } }); }); } /** * 关闭WebSocket连接 */ close() { this.isManualClose = true; // 停止心跳检测 this.stopHeartbeat(); // 清除重连定时器 if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; } // 关闭连接 if (this.socketTask && this.isConnected) { this.socketTask.close({ code: 1000, reason: 'Manual close', success: () => { console.log('WebSocket连接已手动关闭'); }, fail: (error) => { console.error('WebSocket关闭失败', error); } }); } } /** * 重置连接状态,允许重新连接 */ reset() { this.isManualClose = false; this.reconnectAttempts = 0; if (!this.isConnected) { this.connect(); } } } export default WebSocketUtil;