WebSocket 在vue项目中的使用详解_vue websocket
一、代理配置
在使用 WebSocket 时,常常会遇到跨域问题,而通过代理配置可以很好地解决这一问题。在基于 Vite 构建的项目中,我们可以在vite.config.js文件中进行如下配置:
import { defineConfig } from \'vite\'import vue from \'@vitejs/plugin-vue\'export default defineConfig({ plugins: [vue()], server: { host: \'0.0.0.0\', open: true, port: 3001, // 配置后端项目反向代理服务器: proxy: { \'/link\': { target: \'ws://10.11.52.24:8086\', // 对应自己的接口地址 changeOrigin: true, ws: true, }, }, },})
二、WebSocket.js 封装
为了在项目中更方便、高效地使用 WebSocket,避免重复编写连接、发送、接收等操作的代码,我们通常会对 WebSocket 进行封装。以下是一个详细的websocket.js封装示例:
// websocket 实例let wsObj = null;// ws 连接地址let wsUrl = null;// 是否执行重连 true/不执行;false/执行let lockReconnect = false;// 重连定时器let wsCreateHandler = null;// 连接成功,执行回调函数let messageCallback = null;// 连接失败,执行回调函数let errorCallback = null;// 发送给后台的数据let sendDatas = {};import store from \"../store/index\"// import router from \"../router\"// import { ElMessage } from \'element-plus\';/** * 发起 websocket 请求函数 * @param {string} url ws 连接地址 * @param {Object} agentData 传给后台的参数 * @param {function} successCallback 接收到 ws 数据,对数据进行处理的回调函数 * @param {function} errCallback ws 连接错误的回调函数 */export const connectWebsocket = (url, bool, successCallback, errCallback) => { wsUrl = url; let time = new Date() if (bool) { sendDatas = { type: \"login_user\", content: \"用户登录,请求建立连接!\", date: time.getTime() } } else { sendDatas = {} } messageCallback = successCallback; errorCallback = errCallback; createWebSocket();}// 手动关闭 websocket (这里手动关闭会执行 onclose 事件)export const closeWebsocket = () => { if (wsObj) { // log(\'手动关闭 websocket\'); wsObj.close(); // 关闭 websocket // 关闭重连 lockReconnect = true; wsCreateHandler && clearTimeout(wsCreateHandler); // 关闭心跳检查 heartCheck.stop(); }}// 发送消息export const sendMessage = (sendData) => { if (wsObj && wsObj.readyState === WebSocket.OPEN) { wsObj.send(JSON.stringify(sendData)); } else { log(\'WebSocket 连接尚未建立或已关闭,无法发送消息\'); }}// 创建 websocket 函数const createWebSocket = () => { if (typeof (WebSocket) === \'undefined\') { log(\"您的浏览器不支持 WebSocket,无法获取数据\"); return false; } try { wsObj = new WebSocket(wsUrl); store.state.wsObj = wsObj initWsEventHandle(); } catch (e) { log(\"连接异常,开始重连\"); reconnect(); }}const initWsEventHandle = () => { try { wsObj.onopen = (event) => { onWsOpen(event); heartCheck.start(); } wsObj.onmessage = (event) => { onWsMessage(event); heartCheck.start(); } wsObj.onclose = (event) => { // log(\'onclose 执行关闭事件\'); onWsClose(event); } wsObj.onerror = (event) => { // log(\'onerror 执行 error 事件,开始重连\'); onWsError(event); reconnect(); } } catch (err) { // log(\'绑定事件没有成功,开始重连\'); reconnect(); }}const onWsOpen = (event) => { // log(\'CONNECT\'); if (wsObj.readyState === WebSocket.OPEN) { // wsObj.OPEN = 1 wsObj.send(JSON.stringify(sendDatas)); } if (wsObj.readyState === WebSocket.CLOSED) { // wsObj.CLOSED = 3 log(\'wsObj.readyState=3, ws 连接异常,开始重连\'); reconnect(); errorCallback && errorCallback(); }}const onWsMessage = (event) => { const jsonStr = event.data; // log(\'onWsMessage 接收到服务器的数据: \', jsonStr); messageCallback(JSON.parse(jsonStr));}const onWsClose = (event) => { // log(\'DISCONNECT\'); if (event && event.code !== 1000) { // log(\'非正常关闭\'); errorCallback && errorCallback(); reconnect(); }}const onWsError = (event) => { log(\'onWsError: \', event.data); errorCallback && errorCallback();}const log = (message) => { console.log(message);}// 重连函数const reconnect = () => { if (lockReconnect) { return; } log(\'5秒后重连\'); store.state.wsObj = null lockReconnect = true; wsCreateHandler && clearTimeout(wsCreateHandler); wsCreateHandler = setTimeout(() => { log(\'重连...\' + wsUrl); createWebSocket(); lockReconnect = false; log(\'重连完成\'); }, 5000);}// 从浏览器地址中获取对应参数const GetQueryString = (name) => { let reg = new RegExp(\"(^|&)\" + name + \"=([^&]*)(&|$)\", \"i\"); 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); this.timeoutObj = setTimeout(() => { // log(\"心跳检查,发送 ping 到后台\"); try { let time = new Date() const datas = { type: \"ping\", date: time.getTime() }; wsObj.send(JSON.stringify(datas)); } catch (err) { log(\"发送 ping 异常\"); } this.serverTimeoutObj = setTimeout(() => { log(\"没有收到后台的数据,重新连接\"); reconnect(); }, this.timeout) }, this.timeout) }}
这个封装代码涵盖了 WebSocket 的多个核心功能:
- 连接管理:connectWebsocket函数用于发起 WebSocket 连接,接收连接地址、是否携带特定数据、连接成功和失败的回调函数作为参数。在连接建立时,会根据传入的参数决定是否发送特定的初始化数据。
- 消息发送:sendMessage函数负责发送消息,它会先检查 WebSocket 实例的连接状态,只有在连接处于OPEN状态时才会发送消息,确保消息能够正确发送。
- 事件处理:通过initWsEventHandle函数初始化 WebSocket 的各种事件处理函数,包括连接成功(onopen)、接收消息(onmessage)、连接关闭(onclose)和连接错误(onerror)。在这些事件处理函数中,分别执行对应的业务逻辑,如发送初始化数据、处理接收到的数据、重连操作等。
- 重连机制:reconnect函数实现了 WebSocket 连接异常时的重连功能,通过设置定时器,在连接断开或出现错误时等待一段时间后重新尝试连接,并且通过lockReconnect变量避免重复重连。
- 心跳检查:heartCheck对象用于实现心跳检查功能,定期向服务器发送ping消息,若在规定时间内未收到服务器响应,则认为连接异常,触发重连操作,保证 WebSocket 连接的稳定性。
三、在 Vue 中使用
在完成了代理配置和websocket.js的封装后,我们就可以在 Vue 项目中轻松使用 WebSocket 了。以下是在 Vue 组件中的使用示例:
import { connectWebsocket, sendMessage, closeWebsocket } from \'../utils/websocket.js\'import { ref, onMounted } from \"vue\"import { ElMessage } from \'element-plus\';onMounted(() => { connectWebsocket(\'/link\', false, handleMessage, handleError);})/** ws连接成功回调 */const handleMessage = (data: any) => { console.log(data) //操作}/** ws连接错误回调 */const handleError = () => { // ElMessage.error(\'WebSocket 连接出现错误\');}
通过以上代理配置、websocket.js封装以及在 Vue 中的使用这三个步骤,我们就可以在项目中顺利地使用 WebSocket 实现实时通信功能。无论是构建即时聊天应用,还是实时数据展示平台,WebSocket 都能为我们提供强大的技术支持,帮助我们打造出更加高效、流畅的 Web 应用。希望本文的内容能够对大家在 WebSocket 的使用上有所帮助,如果在实践过程中遇到任何问题,欢迎在评论区留言交流!