Vue2 使用WebSocket实现前端与后端的实时通讯

作者 : admin 本文共2882个字,预计阅读时间需要8分钟 发布时间: 2023-11-29 共2人阅读

功能描述: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  {
                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。

在需要监听数据的页面进行this.$bus.$on监听, this.$bus.$off 移除自定义事件监听器。

最后,在退出登录的时候,关闭webSocket

本站无任何商业行为
个人在线分享 » Vue2 使用WebSocket实现前端与后端的实时通讯
E-->