Files
cashier-ipad-new/http/websock - 副本.js
2025-12-25 19:03:44 +08:00

241 lines
7.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;