对 websocket 进行封装 (心跳检测 断开重连 发送事件等等 支持断开重连后发送上次发送的最后一个事件)
代码封装:
// websocketService.js import { ref } from "vue"; const { DEV, VITE_APP_PUSH_WS } = import.meta.env; const { push_ws } = window.WEB_CONFIG; const baseWsUrl = DEV ? VITE_APP_PUSH_WS : push_ws; class WebSocketService { constructor(url) { this.url = url; this.socket = null; this.reconnectTimer = null; this.heartbeatTimer = null; this.socketStatus = false; this.reconnectInterval = 5000; // 重连间隔时间 this.heartbeatInterval = 30000; // 心跳间隔时间 this.websocketObj = ref(null); this.onOpenCallback = null; // 新增用于保存连接成功后的回调函数 this.eventListeners = {}; // 用于存储事件监听器 this.lastSentMessage = null; // 存储最后发送的消息 } initSocket(onOpenCallback) { this.socket = new WebSocket(this.url); this.socket.onopen = () => { clearInterval(this.reconnectTimer); this.socketStatus = true; this.startHeartbeat(); this.websocketObj.value = this.socket; if (onOpenCallback) { onOpenCallback(); } if (this.lastSentMessage) { this.sendMessage(this.lastSentMessage); // 重连后发送最后一条消息 } }; this.socket.onmessage = (event) => { const data = JSON.parse(event.data); const token = window.localStorage.getItem('token') || ''; if (!token) { this.closeSocket(); } if (this.eventListeners[data.event]) { this.eventListeners[data.event].forEach(callback => callback(data)); } }; this.socket.onclose = () => { this.handleSocketClose(); }; this.socket.onerror = () => { this.handleSocketError(); }; } startHeartbeat() { this.heartbeatTimer = setInterval(() => { this.socket.send(JSON.stringify({ event: "heartbeat" })); }, this.heartbeatInterval); } stopHeartbeat() { clearInterval(this.heartbeatTimer); } closeSocket() { this.stopHeartbeat(); this.socket.close(); } handleSocketClose() { console.log("WebSocket closed"); this.socketStatus = false; this.stopHeartbeat(); this.reconnect(); } handleSocketError() { console.log("WebSocket error"); this.socketStatus = false; this.stopHeartbeat(); this.reconnect(); } reconnect() { if (this.reconnectTimer) return; this.reconnectTimer = setInterval(() => { this.initSocket(this.onOpenCallback); }, this.reconnectInterval); } sendMessage(message) { this.lastSentMessage = message; // 存储最后发送的消息 if (this.socket && this.socket.readyState === WebSocket.OPEN) { this.socket.send(message); } else { console.error('WebSocket is not open. Ready state is: ' + (this.socket ? this.socket.readyState : 'N/A')); } } addEventListener(event, callback) { if (!this.eventListeners[event]) { this.eventListeners[event] = []; } this.eventListeners[event].push(callback); } removeEventListener(event, callback) { if (this.eventListeners[event]) { this.eventListeners[event] = this.eventListeners[event].filter(cb => cb !== callback); } } } const wsUrl = `${baseWsUrl}/ws/footballMsg`; const websocketService = new WebSocketService(wsUrl); export const newwebsocketObj = websocketService.websocketObj; export const initWebsocketObj = (onOpenCallback) => { websocketService.initSocket(onOpenCallback); }; export const sendMessage = (message) => { websocketService.sendMessage(message); }; export const closeWebsocket = () => { websocketService.closeSocket(); }; export const addEventListener = (event, callback) => { websocketService.addEventListener(event, callback); }; export const removeEventListener = (event, callback) => { websocketService.removeEventListener(event, callback); };
代码使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | <script setup> import { ref , onMounted, onUnmounted, watch } from 'vue' ; import { initWebsocketObj, sendMessage, addEventListener, removeEventListener, websocketObj } from './websocketService.js' ; const tableData = ref ([]); const standardMatchId = ref ( 'match_id_example' ); // 这是一个示例的 match_id,你可以从路由或其他地方获取 // 处理 WebSocket 消息的回调函数 const handleFootballMessageEvent = (data) => { if (data. event === 'FootballMessageEvent' ) { const { id = '' } = data.payload || {}; if (!tableData.value.length || !id.startsWith(standardMatchId.value)) return ; tableData.value.unshift(data.payload); tableData.value = [... new Set(tableData.value.map(JSON.stringify))].map( JSON.parse ); } }; onMounted(() => { // 初始化 WebSocket initWebsocketObj(() => { // 连接成功后发送初始消息 const message = JSON.stringify({ event : "subMatch" , payload: { FootballMessageEvent: [standardMatchId.value] } }); sendMessage(message); }); // 添加事件监听器 addEventListener( 'FootballMessageEvent' , handleFootballMessageEvent); // 监听 tableData 的变化 watch(tableData, (newValue) => { const standardMatchIds = newValue.map(item => item.standard_match_id + '' ); const params = { BetMarketEvent: standardMatchIds, FootballEvent: standardMatchIds }; const message = JSON.stringify({ event : "subMatch" , payload: params }); sendMessage(message); }); // 组件卸载时移除事件监听器 onUnmounted(() => { removeEventListener( 'FootballMessageEvent' , handleFootballMessageEvent); websocketObj.value && websocketObj.value.close(); }); }); </script> <template> <div> <table> <thead> <tr> <th>Match ID</th> <th>Event</th> </tr> </thead> <tbody> <tr v- for = "item in tableData" :key= "item.standard_match_id" > <td>{{ item.standard_match_id }}</td> <td>{{ item. event }}</td> </tr> </tbody> </table> </div> </template> |
越努力越幸运
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决
2019-06-19 整数反转
2019-06-19 两数之和