vue2 websocket混入
·
以下是WebsocketMixin.js内容,简单易懂,复制之后基本只需要修改地址拼接方式和心跳格式。
// WebsocketMixin.js
import store from '@/store/'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import Vue from 'vue'
export const WebsocketMixin = {
data() {
return {
heartbeatTimer: null, // 心跳定时器
heartbeatTimeoutTimer: null, // 心跳超时检测定时器
reconnectTimer: null, // 重连定时器
heartbeatInterval: 30000, // 心跳间隔 30秒
heartbeatTimeout: 10000, // 心跳超时时间 10秒(等待服务端响应)
lockReconnect: false, // 重连锁
isManualClose: false, // 是否手动关闭
heartbeatPending: false, // 是否有心跳等待响应
heartbeatFailCount: 0, // 心跳连续失败次数
maxHeartbeatFail: 2, // 最大连续失败次数,超过则重连
_originalOnMessage: null
}
},
mounted() {
this.initWebSocket();
},
destroyed: function () {
this.websocketOnclose();
// 清理所有定时器
this.clearAllTimers();
},
methods: {
initWebSocket: function () {
let token = Vue.ls.get(ACCESS_TOKEN)
console.log("------------WebSocket连接准备");
// 获取用户ID
var userId = store.getters.userInfo.id;
if (!this.socketUrl.startsWith('/')) {
this.socketUrl = '/' + this.socketUrl
}
if (!this.socketUrl.endsWith('/')) {
this.socketUrl = this.socketUrl + '/'
}
var url = window._CONFIG['domianURL']
.replace("https://", "wss://")
.replace("http://", "ws://")
+ this.socketUrl + userId
console.log("WebSocket URL:", url);
this.isManualClose = false;
this.heartbeatPending = false;
this.heartbeatFailCount = 0;
if (this.websocketOnmessage && typeof this.websocketOnmessage === 'function') {
this._originalOnMessage = this.websocketOnmessage.bind(this);
}
this.websock = new WebSocket(url, [token]);
this.websock.onopen = this.websocketOnopen;
this.websock.onerror = this.websocketOnerror;
// 使用 Mixin 的 onmessage 处理
this.websock.onmessage = this._handleMessage.bind(this);
this.websock.onclose = this.websocketOnclose;
},
// 统一的 message 处理入口
_handleMessage: function (event) {
try {
// 先尝试解析JSON
let data = event.data;
let parsedData = null;
try {
parsedData = JSON.parse(data);
} catch (e) {
// 不是JSON格式,可能是文本消息
parsedData = data;
}
// ===== 1. 处理心跳响应(Mixin处理,不传递给组件) =====
// 判断是否为心跳响应:{"cmd":"heartcheck","msgTxt":"心跳响应"}
if (parsedData && typeof parsedData === 'object' && parsedData.cmd === 'heartcheck') {
console.log("收到心跳响应:", parsedData.msgTxt || '心跳响应');
this.heartbeatPending = false;
this.heartbeatFailCount = 0;
this.resetHeartbeatTimeout();
return; // 心跳响应不传递给组件
}
// ===== 2. 处理文本心跳响应 =====
if (data === 'pong' || data === 'heartbeat_ack') {
console.log("收到心跳响应:", data);
this.heartbeatPending = false;
this.heartbeatFailCount = 0;
this.resetHeartbeatTimeout();
return; // 心跳响应不传递给组件
}
// ===== 3. 业务消息传递给组件的 websocketOnmessage =====
if (this._originalOnMessage) {
// 保持原始 event 对象
this._originalOnMessage(event);
} else if (this.websocketOnmessage && typeof this.websocketOnmessage === 'function') {
// 如果组件定义了 websocketOnmessage,直接调用
this.websocketOnmessage(event);
} else {
// 没有业务处理器,仅打印日志
console.log("WebSocket收到消息(未处理):", data);
}
} catch (err) {
console.error('_handleMessage error:', err);
}
},
websocketOnopen: function () {
console.log("WebSocket连接成功");
// 重置重连标志
this.lockReconnect = false;
this.heartbeatFailCount = 0;
// 启动心跳
this.startHeartbeat();
},
websocketOnerror: function (e) {
console.error("WebSocket连接发生错误:", e);
this.stopHeartbeat();
this.stopHeartbeatTimeout();
this.reconnect();
},
websocketOnclose: function (e) {
console.log("WebSocket连接关闭:", e);
this.stopHeartbeat();
this.stopHeartbeatTimeout();
// 如果是手动关闭,不触发重连
if (!this.isManualClose) {
this.reconnect();
}
},
websocketSend(text) {
try {
if (this.websock && this.websock.readyState === WebSocket.OPEN) {
this.websock.send(text);
// 发送数据后重置心跳计时器,避免不必要的频繁心跳
this.resetHeartbeat();
} else {
console.warn("WebSocket未连接,无法发送消息");
// 尝试重连
this.reconnect();
}
} catch (err) {
console.error("send failed:", err);
}
},
reconnect() {
var that = this;
if (that.lockReconnect) return;
that.lockReconnect = true;
// 清除之前的重连定时器
if (that.reconnectTimer) {
clearTimeout(that.reconnectTimer);
that.reconnectTimer = null;
}
// 避免重复重连导致请求过多
that.reconnectTimer = setTimeout(function () {
console.info("尝试重连...");
// 先关闭现有连接
if (that.websock) {
that.websock.close();
}
that.initWebSocket();
setTimeout(() => {
that.lockReconnect = false;
}, 1000);
}, 5000);
},
// 启动心跳
startHeartbeat() {
this.stopHeartbeat(); // 先清除旧定时器
this.stopHeartbeatTimeout();
this.heartbeatPending = false;
this.heartbeatFailCount = 0;
this.heartbeatTimer = setInterval(() => {
if (this.websock && this.websock.readyState === WebSocket.OPEN) {
// 发送心跳消息(ping)
const pingMsg = JSON.stringify({ cmd: 'ping' });
this.websock.send(pingMsg);
console.log("发送心跳 ping");
// 标记心跳等待响应
this.heartbeatPending = true;
// 启动心跳超时检测
this.startHeartbeatTimeout();
} else {
console.warn("WebSocket未连接,停止心跳");
this.stopHeartbeat();
this.stopHeartbeatTimeout();
// 如果连接断开了,尝试重连
if (!this.isManualClose) {
this.reconnect();
}
}
}, this.heartbeatInterval);
},
// 停止心跳
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
},
// 启动心跳超时检测
startHeartbeatTimeout() {
this.stopHeartbeatTimeout();
this.heartbeatTimeoutTimer = setTimeout(() => {
// 如果心跳超时且还在等待响应
if (this.heartbeatPending) {
console.warn("心跳超时,未收到服务端响应");
this.heartbeatFailCount++;
if (this.heartbeatFailCount >= this.maxHeartbeatFail) {
console.error(`心跳连续失败${this.heartbeatFailCount}次,触发重连`);
this.heartbeatPending = false;
this.heartbeatFailCount = 0;
// 触发重连
if (!this.isManualClose) {
this.stopHeartbeat();
this.stopHeartbeatTimeout();
this.reconnect();
}
} else {
// 继续等待下一次心跳
this.heartbeatPending = false;
console.log(`心跳失败次数: ${this.heartbeatFailCount}/${this.maxHeartbeatFail}`);
}
}
}, this.heartbeatTimeout);
},
// 停止心跳超时检测
stopHeartbeatTimeout() {
if (this.heartbeatTimeoutTimer) {
clearTimeout(this.heartbeatTimeoutTimer);
this.heartbeatTimeoutTimer = null;
}
},
// 重置心跳超时检测
resetHeartbeatTimeout() {
// 如果还有心跳在等待,重置超时计时器
if (this.heartbeatPending) {
this.startHeartbeatTimeout();
}
},
// 重置心跳
resetHeartbeat() {
// 收到消息或发送消息后重置心跳计时器
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = setInterval(() => {
if (this.websock && this.websock.readyState === WebSocket.OPEN) {
// 发送心跳消息(ping)
const pingMsg = JSON.stringify({ cmd: 'ping' });
this.websock.send(pingMsg);
console.log("发送心跳 ping");
this.heartbeatPending = true;
this.startHeartbeatTimeout();
} else {
console.warn("WebSocket未连接,停止心跳");
this.stopHeartbeat();
this.stopHeartbeatTimeout();
if (!this.isManualClose) {
this.reconnect();
}
}
}, this.heartbeatInterval);
}
},
// 清理所有定时器
clearAllTimers() {
this.stopHeartbeat();
this.stopHeartbeatTimeout();
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
},
// 手动关闭WebSocket(可外部调用)
closeWebSocket() {
this.isManualClose = true;
this.stopHeartbeat();
this.stopHeartbeatTimeout();
if (this.websock) {
this.websock.close();
}
}
}
}
使用方法:
1、页面引入
import { WebsocketMixin } from '@/mixins/WebsocketMixin'
2、页面注册
export default 中增加
mixins: [WebsocketMixin]
3、data中定义地址
socketUrl: 'websocket',
4、methods中写接收方法
websocketOnmessage: function (e) {
console.log("WebSocket收到消息:", e.data);
try {
const data = e.data;
//你的业务逻辑
} catch (err) {
console.log('websocketOnmessage error:', err);
}
},
至此结束。
更多推荐
所有评论(0)