vue2使用webSocket双向通讯

这篇具有很好参考价值的文章主要介绍了vue2使用webSocket双向通讯。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基于webSocket实现双向通信,使用webworker保持心跳。

由于浏览器的资源管理策略会暂停或限制某些资源的消耗,导致前端心跳包任务时效,后端接收不到webSocket心跳主动断开,因此需要使用webworker保持心跳

vue2 websocket,websocket,vue,web worker

  1. 引入webworker文章来源地址https://www.toymoban.com/news/detail-855461.html

    npm install worker-loader -D
  2. vue.config配置webworker
    module.exports = {
     chainWebpack: config => {
            // web worker配置
            config.module
                .rule('worker')
                .test(/\.worker\.js$/)
                .use('worker-loader')
                .loader('worker-loader')
                .options({
                    inline: 'fallback',
                    filename: 'workerName.[hash].worker.js'
                })
                .end();
            // 解决worker 热更新
            config.module.rule('js').exclude.add(/\.worker\.js$/);
        }
    }
  3. 新增websocket.js创建websocket单例
    const token = null;
    const WsUrl = null;
    import store from '@/store'
    import { WS_CODE_ENUM, TASK_TYPE_ENUM } from 'config/enum';
    import { startNetworkListener, stopNetworkListener, startHeartBeat, stopHeartBeat, openReconnect, clearRetry } from './wsUtils'
    
    /**
     * WebSocket对象实例
     */
    class WebSocketUtil {
         constructor () {
            /**
             * ws对象,全局共用同一个对象
             */
            this.socket = null
            /**
             * WS是否重连标识
             * 0:非重连,1:重连,
             * ws建立连接参数
             */
            this.reconnect = 0
            /**
             * 前后端心跳服务端响应次数
             * ws连接建立时重置
             * 第一次收到服务端响应,车辆未连接且非ws重连时,打开车辆连接弹窗
             * 接收到后端心跳响应累加
             */
            this.pongNum = 0
            /**
             * 前后端心跳后端未响应次数
             * 前端发送心跳时加1
             * 后端有响应时清空
             * 车辆连接成功后, 未响应次数≥2,说明后端两次未响应,自动开启前后端重连
             */
            this.heartBeatRsp = 0
            /**
             * 前后端ws重连尝试次数,最多三次,
             * 重连累加,重连结束重置为0
             * 三次均重连失败,断开ws连接,清空单车诊断业务缓存,跳转到车辆连接页面
             */
            this.retryTime = 0
            /**
             * 前后端重连任务,重试最多持续10秒,若超过10秒,则按照重试失败处理,
             * 第一次开启重连时,开启任务,
             * 重连成功、10秒未连接成功关闭任务,
             * 重连失败时,若用户处于车辆连接页面,toast提示; 若用户处于单车诊断页面则跳转回车辆连接页面;若用于处于非单车诊断toast提示
             */
            this.retryTimer = 0
            /**
             * 重连任务toast
             * 重连开始开启
             * 重连结束关闭、重置
             */
            this.reconnectMsg = null
            /**
             * 重连任务全局遮罩
             * 重连开始开启
             * 重连结束关闭、重置
             */
            this.reconnectLoading = null
            /**
             * 页面超时任务
             * 最后一次下发或最后一次上报开始时间点
             * 11分钟内无任务下发、任务上报判定页面超时
             * 浏览器刷新、车辆连接成功后开启
             * ws断开连接、重连过程中关闭
             * 页面超时关闭ws,跳转单车连接页面
             */
            this.pageTimer = null
            /**
             * token续期任务,每5分钟一次,
             * 浏览器刷新、车辆连接成功后开启
             * ws断开连接、重连过程中关闭
             */
            this.tokenPolling = null
            /**
             * 开启一个独立线程,处理心跳包任务
             * setInterval是基于当前页面的定时任务,如果浏览器切换窗口/隐藏时会停止任务,这时后端接收不到前端发送的心跳包,会触发断开ws
             * 使用webWorker线程,可以突破浏览器默认机制
             * 启动心跳后,开启独立线程,发送心跳包
             * 心跳关闭时关闭独立线程
             */
            this.worker = null
        }
        
            /**
         * 建立WS连接
         * @param {*} reconnect 是否重连,0:非重连,1:重连
         * @param {*} vin 车辆VIN码
         * @param {*} userName 用户信息
         * @param {*} needAuth 车机授权
         * @description 每次建立ws连接,重置服务端响应次数
         */
        connect (reconnect = 0, vin, userName, needAuth) {
            this.socket = new WebSocket(`${WsUrl}/${vin}/${userName}/${reconnect}/${needAuth}`, getToken());
            this.reconnect = reconnect
            this.pongNum = 0 // 服务端响应次数
            this.socket.onopen = this.onOpen.bind(this);
            this.socket.onmessage = this.onMessage.bind(this);
            this.socket.onerror = this.onError.bind(this);
            this.socket.onclose = this.onClose.bind(this);
        }
        
        /**
         * 开启WebSocket
         * 启动心跳任务
         * 启动网络监听
         */
        onOpen () {
            // 启动心跳
            startHeartBeat()
            // 启动网络监听
            startNetworkListener()
        }
        /**
         * WebSocket响应业务处理
         * 1:服务端响应次数累加
         * 2:第一次收到服务端响应,根据是否重连,响应不通的车辆连接业务
         * 3:服务端未响应次数重置
         * 4:车辆已连接且处于重连过程时,关闭重连业务,提示重连成功
         */
        onMessage ({ data }) {
            // 服务端响应次数累加
            this.pongNum++
            // 收到服务端第一次信息
            if (this.pongNum === 1) {
                // 非重连,第一次收到服务端信息,开启车辆连接弹窗
                if (this.reconnect === 0) // TODO 业务操作
                // 重连继续心跳计时
                else TODO 业务操作
            }
            // 心跳响应无需处理
            if (data === 'pong') {
                // 服务端未响应次数重置
                this.heartBeatRsp = 0
                // 车辆已连接,存在重连
                if (store.getters.connected && this.retryTime > 0) {
                    clearRetry()
                    Message.success('重连成功')
                }
                return
            }
            // 业务操作
        }
    
            /**
         * WebSocket关闭处理
         * 1:关闭网络监听
         * 2:前后端重连业务
         * 3:连接过程中ws断开异常处理
         * 4: 退出业务
         */
        onClose (event) {
            console.log('WebSocket关闭:', event.code, event.reason);
            // 关闭网络监听
            stopNetworkListener()
            // 服务端未响应次数 ≥ 2,需要重连
            if (this.heartBeatRsp >= 2) return openReconnect()
            this.disconnect()
        }
    
        /**
         * 断开ws连接
         * 关闭心跳包、清空tokne续期任务、关闭页面超时
         */
        clearWs () {
            this.socket?.close();
            this.socket = null;
            stopHeartBeat()
        }
    
        /**
         * 退出单车诊断业务
         * @param {boolean} clearAll 是否清空所有state数据
         * 1: 车辆已连接,记录断开连接时间,用于车辆连接页面-车辆连接按钮退出后5秒不能连接判断
         * 2:断开ws连接,
         * 3: 关闭心跳包、清空tokne续期任务、关闭页面超时判定
         * 4:清空重连loading、toast提示、关闭重连超时任务
         * 5: 调用退出实时模式接口,通知后端退出实施模式
         * 6:清空单车诊断相关浏览器缓存
         */
        disconnect (clearAll = false) {
            console.log('WebSocket断开连接')
            // 记录断开连接日期
            if (store.getters.connected) storage.set('WS_LAST_CLOSE_TIME', dayjs().unix())
            this.clearWs()
            clearRetry()
            Message.closeAll();
            // 重置信息
            store.commit('RESET_STATE')
        }
    }
        // 懒汉模式
    const LazySingleton = (function () {
        let _instance = null
        return function () {
            return _instance || (_instance = new WebSocketUtil())
        }
    })()
    
    const websocket = new LazySingleton()
    export default websocket
  4. websocket工具类wsUtils.js
    import websocket from '@/diagnostic/websocket'
    import store from '@/store'
    import { Message, Loading } from 'element-ui';
    import WsWorker from './ws.worker.js'
    /**
     * ws通信建立成功开启心跳包任务;
     * 每5秒发送一次心跳包;
     * 每次发送心跳包累加服务端未响应次数【heartBeatRsp】;
     * 服务端未响应次数【heartBeatRsp】 ≥ 2,判定服务端响应超,开启前后端重连;
     */
    export const startHeartBeat = () => {
        websocket.socket && websocket.socket.readyState === WebSocket.OPEN &&     websocket.socket.send('ping');
        websocket.worker = new WsWorker()
        websocket.worker.postMessage({ type: 'start' })
        websocket.worker.onmessage = (e) => {
            const { type } = e.data
            if (type === 'send') {
                // 发送心跳ping
                sendPing()
            }
        }
    }
    
    const sendPing = () => {
        // 服务端未响应次数累加
        websocket.heartBeatRsp++
        // 车辆已连接,服务端响应次数≥2,鉴定为服务端响应超时,断开ws连接,开启重连
        if (store.getters.connected && websocket.heartBeatRsp >= 2) websocket.clearWs()
        websocket.socket && websocket.socket.readyState === WebSocket.OPEN && websocket.socket.send('ping');
    }
    
    /**
     * ws断开连接,关闭心跳包任务,
     * 清空tokne续期任务,关闭页面超时判定
     */
    export const stopHeartBeat = () => {
        // 关闭心跳
        websocket.worker?.postMessage({ type: 'stop' })
        // 清空轮询
        clearInterval(websocket.tokenPolling)
        websocket.tokenPolling = null
        // 关闭页面超时判定
        clearTimeout(websocket.pageTimeout)
        websocket.pageTimeout = null
        // 关闭心跳包独立线程
        websocket.worker?.terminate()
    }
    /**
     * 开启重连
     * 每次重连需要间隔三秒
     * 三次重连失败,toast提示,退出单车诊断业务
     */
    export const openReconnect = async () => {
        switch (websocket.retryTime) {
        case 0:
            retryConnect()
            break;
        case 1:
        case 2:
            await sleep(3000)
            retryConnect()
            break;
        default:
            Message.error('当前您的网络不稳定,车辆连接已断开,请重新进行连接')
            websocket.disconnect()
            break;
        }
    }
    export const sleep = (ms) => {
        return new Promise((resolve) => setTimeout(resolve, ms))
    }
    /**
     * 前后端重连,重连次数累加
     * 1:开启重连全屏loading、toast提示
     * 2:关闭旧连接
     * 3:第一次重连开启重连超时任务
     * 4:开始重连
     */
    export const retryConnect = () => {
        // 重连次数累加
        websocket.retryTime++
        // 开启全屏loading
        websocket.reconnectLoading = Loading.service({ fullscreen: true });
        websocket.reconnectMsg?.close()
        websocket.reconnectMsg = Message.warning({
            message: `当前您的网络环境不稳定,正在进行第${websocket.retryTime}次重连,请等待`,
            duration: 0
        })
        // 关闭旧连接
        websocket.clearWs()
        // 第一次重连开启重连超时任务
        if (websocket.retryTime === 1) startRetryTimer()
        // 开启重连
        websocket.connect(1)
    }
    
    /**
     * 重连超时任务
     * 重连三次时间不能超过10秒,超过10秒按照重连失败处理
     * 1:开启重连超时任务前,如果存在重连超时任务,先关闭
     * 2:开启超时重连任务,时间10秒
     * 3:10秒后,服务端未响应次数不等于0 判定重连超时,退出单车诊断业务
     */
    const startRetryTimer = () => {
        // 1:开启重连超时任务前,如果存在重连超时任务,先关闭
        stopRetryTimer()
        // 2:暂停车云心跳计时
        store.commit('connect/STOP_CONNECT_TIMER')
        // 3:开启超时重连任务,时间10秒
        websocket.retryTimer = setTimeout(() => {
            // 4:10秒后,服务端未响应次数不等于0 判定重连超时,退出单车诊断业务
            if (websocket.retryTime != 0) {
                Message.error('当前您的网络不稳定,车辆连接已断开,请重新进行连接')
                websocket.disconnect()
            }
        }, 1000 * 10)
    }
    
    /**
     * 关闭重连超时任务
     */
    const stopRetryTimer = () => {
        if (websocket.retryTimer) {
            clearTimeout(websocket.retryTimer)
            websocket.retryTimer = null
        }
    }
    /**
     * 关闭重连流程
     * 清空重连全屏loading、toast提示
     * 重置重连次数、关闭重连超时任务、重置服务端未响应次数
     */
    export const clearRetry = () => {
        websocket.reconnectLoading?.close()
        websocket.reconnectLoading = null
        websocket.reconnectMsg?.close()
        websocket.reconnectMsg = null
        websocket.retryTime = 0
        websocket.heartBeatRsp = 0
        stopRetryTimer()
    }
    
    /**
     * 监听网络连接状态,
     * ws建立通信后开启
     */
    export const startNetworkListener = () => {
        window.addEventListener('offline', offline)
    }
    
    /**
     * ws连接断开后,停止网络监听
     */
    export const stopNetworkListener = () => {
        window.removeEventListener('offline', offline)
    }
    /**
     * 监听网络连接状态
     * 监听到网络中断:主动断开当前ws连接;网络中断后onclose事件会失效,需要主动提前断开ws
     * 判断车辆是否已连接,如果车辆已连接需要开启前后端三次重连
     */
    const offline = (e) => {
        // 网络中断
        if (e.type === 'offline') {
            // 车辆已连接
            if (store.getters.connected) websocket.heartBeatRsp = 2 // 后端未响应次数≥2开启重连
            // 主动断开当前ws连接
            websocket.clearWs()
        }
    }
    
  5. 创建webWorker进程用来处理ws心跳ws.worker.js
    /**
     * 前后端心跳包任务,ws连接建立后每5秒发送一次,由前端主动发起,后端响应
     * ws断开心跳任务清空
     */
    let heartBeatTimer = null
    onmessage = (e) => {
        const { type } = e.data;
        if (type === 'start') {
            heartBeatTimer = setInterval(() => {
                console.log('WebSocket is sending heartbeat');
                postMessage({ type: 'send' });
            }, 1000 * 5);
        }
        if (type === 'stop') {
            // 清除定时器
            clearInterval(heartBeatTimer)
            heartBeatTimer = null
            console.log('心跳包任务停止成功')
        }
    }
    
  6. 在组件中使用
    import websocket from '@/websocket'
    
    export default {
        mounted () {
            websocket.connect()
        }
    }

到了这里,关于vue2使用webSocket双向通讯的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue中利用websocket实现实时通讯

    目录 一、webSocket是什么? 二、WebSocket 原理 三、WebSocket 特点 四、WebSocket 应用场景 五、使用步骤 1.安装相关依赖 2.在Vue组件中创建WebSocket连接 3.向服务器发送消息 4.关闭WebSocket连接 总结         WebSocket 是一种基于 TCP 协议的全双工通信协议,它可以在单个 TCP 连接上实现

    2024年02月08日
    浏览(46)
  • vue2 封装 webSocket 开箱即用

    第一步:    下载 webSocket  第二步:   需要在 main.js 中 引入  第三步:     封装相关的连接和断开    相关代码!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  第四步:  引入使用 到这步接收信息已经OK了(记得和后端配合)    使用

    2024年02月14日
    浏览(38)
  • Vue中如何利用websocket实现实时通讯

    原理很简单,有点像VUE中的EventBus,用emit和on传来传去 首先我们可以先去自己去用node搭建一个本地服务器 步骤如下 1.新建一个app.js,然后创建pagejson.js文件,输入以下指令 npm init -y 2.下载 express包 pnpm  i  express 3.在app.js里面去进行导包创建express实例   4.重启服务器,我们可

    2023年04月08日
    浏览(41)
  • SpringBoot+Vue整合WebSocket实现实时通讯

            在开发过程中,我们经常遇到需要对前台的列表数据,实现实时展示最新的几条数据,或者是调度的任务进度条实现实时的刷新......,而对于这种需求,无状态的http协议显然无法满足我们的需求,于是websocket协议应运而生。websocket协议本质上是一个基于tcp的协议

    2024年02月13日
    浏览(40)
  • 前端实现websocket通信讲解(vue2框架)

    前言 :最近接到的需求是前端需要实现一个全局告警弹窗,如果使用ajax请求http接口只能用定时器定时去请求是否有告警,这样既消耗资源,又不能实时监测到告警信息。所以这个时候就可以采用websocket来实现通信,因为websocket不用请求一次才响应一次,它可以实现服务器主

    2024年02月12日
    浏览(35)
  • web网页端使用webSocket实现语音通话功能(SpringBoot+VUE)

    最近在写一个web项目,需要实现web客户端之间的语音通话,期望能够借助webSocket全双工通信的方式来实现,但是网上没有发现可以正确使用的代码。网上能找到的一个代码使用之后 只能听到“嘀嘀嘀”的杂音 解决方案: 使用Json来传递数据代替原有的二进制输入输出流 技术

    2024年02月02日
    浏览(116)
  • 远程服务和web服务和前端,三方通过socket和websocket进行双向通信传输数据

    1. 什么是socket? 在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。 2. 什么是websocket? WebSocket是一种网络通信协议,是HTML5新增的特性,

    2024年02月15日
    浏览(56)
  • websocket实现聊天室(vue2 + node)

    需求分析如图: 搭建的项目结构如图: 前端步骤: vue create socket_demo (创建项目) views下面建立Home , Login组件 路由里面配置路径 Home组件内部开启websocket连接 前端相关组件代码: Login组件 Home组件 router/index.js 后端步骤: 在项目外层创建server文件夹(src目录同级) npm init -y创建

    2024年01月22日
    浏览(50)
  • WebSocket全栈搭建(Java + Vue2) 上

    路途漫漫,行则将至 一般来讲,我们传统的前后端分离设计下,前后端通讯一般都是前端发送一个http请求,之后后端处理,然后返回给前端,这样的设计下,其实就是类似于一种单工的通信模式,这种模式下可能无法满足一些特定的场景: 比如我们存在一个后台的定时任务

    2024年01月17日
    浏览(34)
  • SpringBoot和Vue2集成WebSocket,实现聊天室功能

    springboot集成websocket实现聊天室的功能。如有不足之处,还望大家斧正。

    2024年01月23日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包