/**
|
* 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) {
|
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;
|