Loading... ### 简言 项目需要对接长链,客户端与服务端保持会话,以便客服及时查看需要审核的内容。所以此功能我们师徒二人来共同来研究完成。 ### 操作 #### 第一步:封装websocket.js文件 首先需要创建websocket文件,方便后续多次调用,下面是连接和检查心跳的方法: ```js // websocket实例 let wsObj = null; // ws连接地址 let wsUrl = null; // let userId = null; // 是否执行重连 true/不执行 ; false/执行 let lockReconnect = false; // 重连定时器 let wsCreateHandler = null; // 连接成功,执行回调函数 let messageCallback = null; // 连接失败,执行回调函数 let errorCallback = null; // 发送给后台的数据 let sendDatas = {}; /** * 发起websocket请求函数 * @param {string} url ws连接地址 * @param {Object} agentData 传给后台的参数 * @param {function} successCallback 接收到ws数据,对数据进行处理的回调函数 * @param {function} errCallback ws连接错误的回调函数 */ export const connectWebsocket = (url, agentData, successCallback, errCallback) => { wsUrl = url; createWebSoket(); messageCallback = successCallback; errorCallback = errCallback; sendDatas = agentData; } // 手动关闭websocket (这里手动关闭会执行onclose事件) export const closeWebsocket = () => { if (wsObj) { writeToScreen('手动关闭websocket'); wsObj.close() // 关闭websocket // wsObj.onclose() // 关闭websocket(如果上面的关闭不生效就加上这一条) // 关闭重连 lockReconnect = true; wsCreateHandler && clearTimeout(wsCreateHandler); // 关闭心跳检查 heartCheck.stop(); } } // 创建ws函数 const createWebSoket = () => { if (typeof (WebSocket) === 'undefined') { writeToScreen("您的浏览器不支持WebSocket,无法获取数据"); return false } // const host = window.location.host; // userId = GetQueryString("userId"); // wsUrl = "ws://" + host + "/websoket" + userId; try { wsObj = new WebSocket(wsUrl); initWsEventHandle(); } catch (e) { writeToScreen("连接异常,开始重连"); reconnect(); } } const initWsEventHandle = () => { try { // 连接成功 wsObj.onopen = (event) => { onWsOpen(event); heartCheck.start(); } // 监听服务器端返回的信息 wsObj.onmessage = (event) => { onWsMessage(event); heartCheck.start(); } wsObj.onclose = (event) => { writeToScreen('onclose执行关闭事件'); onWsClose(event); } wsObj.onerror = (event) => { writeToScreen('onerror执行error事件,开始重连'); onWsError(event); reconnect(); } } catch (err) { writeToScreen('绑定事件没有成功,开始重连'); reconnect(); } } const onWsOpen = (event) => { writeToScreen('CONNECT'); // // 客户端与服务器端通信 // wsObj.send('我发送消息给服务端'); // 添加状态判断,当为OPEN时,发送消息 if (wsObj.readyState === wsObj.OPEN) { // wsObj.OPEN = 1 // 发给后端的数据需要字符串化 wsObj.send(JSON.stringify(sendDatas)); } if (wsObj.readyState === wsObj.CLOSED) { // wsObj.CLOSED = 3 writeToScreen('wsObj.readyState=3, ws连接异常,开始重连'); reconnect(); errorCallback(event); } } const onWsMessage = (event) => { const jsonStr = event.data; writeToScreen('onWsMessage接收到服务器的数据: ', jsonStr); messageCallback(jsonStr); } const onWsClose = (event) => { writeToScreen('DISCONNECT'); // e.code === 1000 表示正常关闭。 无论为何目的而创建, 该链接都已成功完成任务。 // e.code !== 1000 表示非正常关闭。 console.log('onclose event: ', event) if (event && event.code !== 1000) { writeToScreen('非正常关闭'); errorCallback(event); // 如果不是手动关闭,这里的重连会执行;如果调用了手动关闭函数,这里重连不会执行 reconnect(); } } const onWsError = (event) => { writeToScreen('onWsError: ', event.data); errorCallback(event); } const writeToScreen = (massage) => { console.log(massage); } // 重连函数 const reconnect = () => { if (lockReconnect) { return; } writeToScreen('3秒后重连'); lockReconnect = true; // 没连接上会一直重连,设置延迟避免请求过多 wsCreateHandler && clearTimeout(wsCreateHandler); wsCreateHandler = setTimeout(() => { writeToScreen('重连...' + wsUrl); createWebSoket(); lockReconnect = false; writeToScreen('重连完成'); }, 3000); } // 从浏览器地址中获取对应参数 const GetQueryString = (name) => { let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); // 获取url中 ? 符后的字符串并正则匹配 let r = window.location.search.substr(1).match(reg); let context = ""; r && (context = r[2]); reg = null; r = null; return context; } // 心跳检查(看看websocket是否还在正常连接中) let heartCheck = { timeout: 15000, timeoutObj: null, serverTimeoutObj: null, // 重启 reset() { clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); this.start(); }, // 停止 stop() { clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); }, // 开启定时器 start() { this.timeoutObj && clearTimeout(this.timeoutObj); this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj); // 15s之内如果没有收到后台的消息,则认为是连接断开了,需要重连 this.timeoutObj = setTimeout(() => { writeToScreen("心跳检查,发送ping到后台"); try { const datas = { ping: true }; wsObj.send(JSON.stringify(datas)); } catch (err) { writeToScreen("发送ping异常"); } console.log("内嵌定时器this.serverTimeoutObj: ", this.serverTimeoutObj) // 内嵌定时器 this.serverTimeoutObj = setTimeout(() => { writeToScreen("没有收到后台的数据,重新连接"); reconnect(); }, this.timeout) }, this.timeout) } } `` ``` 在src的utils目录中新建文件:ws.js,并将上述代码复制进去。 #### 第二步:在vue中局部调用 ```js // 此处需要注意路径,用相对路径即可 //connectWebsocket(建立长链接的方法)、closeWebsocket(关闭长链接方法) import { connectWebsocket, closeWebsocket } from '../utils/ws' ``` > 如果在main.js中加载上述代码,则是全局调用 #### 第三步:建立链接,接收数据 ```js connectWebsocket( // 测试地址 'ws://127.0.0.1:9901/client/1', // 传递给后台的数据 { openexe: 'openexe' }, // 成功拿到后台返回的数据的回调函数 (data) => { // 在此可以接收到来自服务器的成功调用记录,但是需要判断好需要处理的参数,因为此方法会频繁调用,包括监测心跳💓包也会走此方法,所以需要特殊注意。根据第一步封装的ws.js文件中的设置,心跳监测周期为15秒。 console.log('成功的回调函数, 接收到的data数据: ', data) }, // websocket连接失败的回调函数 (err) => { console.log('失败的回调函数', err) } ) ``` ### 总结 > 整个过程比较简单,不需要加载其他的npm组件; **需要注意的点:** - 第三步的成功方法中的data为string格式,需要转换成json使用。 ```js (data) => { // 在此可以接收到来自服务器的成功调用记录,但是需要判断好需要处理的参数,因为此方法会频繁调用,包括监测心跳💓包也会走此方法,所以需要特殊注意。根据第一步封装的ws.js文件中的设置,心跳监测周期为15秒。 //将data转换成json格式 data = JSON.parse(data); console.log('成功的回调函数, 接收到的data数据: ', data) }, ``` - closeWebsocket是关闭长链接方法,备注方便后续查看。 - websocket协议头为ws,区别于http,需要注意使用! 最后修改:2024 年 12 月 04 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏