功能描述:WebSocket是一种在单个TCP连接上进行全双工通信的协议,它能够在客户端和服务器之间建立持久的连接,使得实时通讯成为可能。在前端开发中,WebSocket通常用于实现实时消息推送、实时数据更新等功能,为用户提供更流畅、即时的体验
本文将介绍如何在前端项目中利用WebSocket实现与后端的实时通讯,并结合具体的代码示例进行讲解。
实现单例模式的SocketService类
在本文中,我们将使用一个名为SocketService
的类来封装WebSocket的相关操作,并通过单例模式确保在整个应用程序中只有一个SocketService
实例存在。这样可以避免多次实例化和重复连接服务器的问题,同时方便在应用程序的不同模块中共享同一个SocketService
实例,实现统一的数据传输和处理逻辑。
创建utils文件夹--->websocket.js文件
import { LoginWebSocketApi } from "@/request/api";export default class SocketService { // 用于实现单例模式的写法 // 可以确保在整个应用程序中只有一个SocketService实例存在,避免了多次实例化和重复连接服务器的问题。通过单例模式,可以方便地在应用程序的不同模块中共享同一个SocketService实例,实现统一的数据传输和处理逻辑。 static instance = null; static get Instance() { if (!this.instance) { this.instance = new SocketService() } return this.instance } ws = null // 标识是否连接成功 connected = false // 重试的次数 sendRetryCount = 0 // 重连的次数 connectRetryCount = 0 // 存储回调函数 // callBackMapping = {} heartbeatInterval = null; // 连接服务器的方法 connect(vue) { // 连接服务器 if (!window.WebSocket) { return console.log("浏览器不支持webSocket") } if (!localStorage.getItem("token")) { console.log('没有token,不连接WebSocket'); return; } this.ws = new WebSocket("wss://你的地址"); // 连接成功的事件 this.ws.onopen = () => { console.log("连接成功"); this.connected = true; this.connectRetryCount = 0; clearTimeout(this.heartbeatInterval); this.start(); } // 连接失败的事件 this.ws.onclose = () => { console.log("连接失败") this.connected = false; if (this.connectRetryCount <= 100) { this.connectRetryCount++ } setTimeout(() => { this.connect(vue) }, this.connectRetryCount * 500) } // 收到数据的事件 this.ws.onmessage = (res) => { // console.log("获取信息", res.data) try { console.log('接收消息', res.data); let data_arr = JSON.parse(res.data); let type = data_arr.type; // 处理不同类型的消息 switch (type) { case 'login': this.login_websocket(data_arr.client_id); break; case 'charge_normal_end': vue.$bus.$emit('charge_normal_end', data_arr); break; case 'shots_count_change': vue.$bus.$emit('shots_count_change', data_arr); break; default: break; } } catch (e) { console.log('e', e); } } } login_websocket(client_id) { LoginWebSocketApi({ client_id: client_id, ws_group: '首页' }).then((webRes) => { let ddd = { type: 'login_success', login_id: webRes.data.login_id }; this.send(JSON.stringify(ddd)); console.log('发送登录消息', ddd); this.manual_colse = false; }).catch((err) => { console.log('33err', err) }); } // 发送 send(data) { // this.ws.send(data) if (this.connected) { this.sendRetryCount = 0; this.ws.send(data) } else { this.sendRetryCount++ setTimeout(() => { }, this.sendRetryCount * 500) } } // 关闭socket连接 close() { if (this.ws) { this.ws.close(); this.connected = false; // 更新连接状态 clearInterval(this.heartbeatInterval); // 清除心跳检测定时器 } } // 开启心跳检测 start() { this.heartbeatInterval = setInterval(() => { this.data = { type: "ping" }; this.send(JSON.stringify(this.data)); }, 5000); }}
注意点:在webSocket.js
这样的非Vue组件文件中,this
并不指向Vue实例,因此无法直接通过this.$bus
来访问事件总线,所以我这用的是vue.$bus.$emit.
在main.js文件中:我的事件总线是挂载在Vue原型上的,那么我在组件中就可以使用this.$bus
来访问它
Vue.use(ElementUI);new Vue({ router, store, render: h => h(App), beforeCreate() { Vue.prototype.$bus = this }}).$mount('#app')
在App.vue文件里的mounted
生命周期钩子中执行,在登录成功后调用了SocketService.Instance.connect(this)
来连接WebSocket。
<script>import SocketService from "./utils/websocket";import { AutoLoginApi } from "@/request/api";export default { mounted() { const token = localStorage.getItem("token"); if (token) { AutoLoginApi() .then(res => { if (token) { SocketService.Instance.connect(this); } }) .catch(error => { console.log("自动登录error", error); }); } }};</script>
在需要监听数据的页面进行this.$bus.$on监听, this.$bus.$off 移除自定义事件监听器。
<script>export default { data() { return { }; }, beforeDestroy() { console.log("销毁"); this.stopListening(); }, created() { this.startListening(); }, methods: { startListening() { this.$bus.$on("charge_normal_end", this.on_res_msg_charge_normal_end); this.$bus.$on("shots_count_change", this.on_res_msg_shots_count_change); }, stopListening() { this.$bus.$off("charge_normal_end", this.on_res_msg_charge_normal_end); this.$bus.$off("shots_count_change", this.on_res_msg_shots_count_change); }, on_res_msg_charge_normal_end(data) { //在这里处理逻辑 console.log("输出信息查看", data); }, on_res_msg_shots_count_change(data) { console.log("输出信息查看", data); } }};</script>
最后,在退出登录的时候,关闭webSocket
<script>import SocketService from "@/utils/websocket";export default { data() { return { }; }, methods: { // 退出登录 handleCommand(command) { // 清除token localStorage.removeItem("token"); // 关闭WebSocket连接 if (SocketService.Instance.connected) { console.log("关闭WebSocket连接"); SocketService.Instance.ws.close(); } } }};</script>