vue2使用webSocket双向通讯

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

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

  1. 引入webworker

    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 = reconnectthis.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 = nullreturn 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.dataif (type === 'send') {// 发送心跳pingsendPing()}}
    }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++// 开启全屏loadingwebsocket.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 = nullwebsocket.reconnectMsg?.close()websocket.reconnectMsg = nullwebsocket.retryTime = 0websocket.heartBeatRsp = 0stopRetryTimer()
    }/*** 监听网络连接状态,* 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 = nullconsole.log('心跳包任务停止成功')}
    }
    

  6. 在组件中使用
    import websocket from '@/websocket'export default {mounted () {websocket.connect()}
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/760922.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于安卓调用文件浏览器(一)打开并复制

背景 最近在做一个硬件产品,安卓应用开发。PM抽风,要求从app打开文件浏览器,跳转到指定目录,然后可以实现文件复制粘贴操作。 思考 从应用开发的角度看,从app打开系统文件浏览器并且选择文件,这是很常见…

.NET Framework 服务实现监控可观测性最佳实践

环境信息 系统环境:Windows Server开发语言:.NET Framework > 4.6.1APM探针包:ddtrace 准备工作 安装 Datakit 主机部署: 主机安装 - 观测云文档 打开采集 APM 采集器 Windows 主机配置 # 到如下路径,把ddtr…

广东省30m二级分类土地利用数据(矢量)

广东省,地处中国大陆最南部,属于东亚季风区,从北向南分别为中亚热带、南亚热带和热带气候,是中国光、热和水资源最丰富的地区之一。主要河系为珠江的西江、东江、北江和三角洲水系以及韩江水系。广东省面积为17.977万平方公里&…

vue+element 前端实现增删查改+分页,不调用后端

前端实现增删查改分页&#xff0c;不调用后端。 大概就是对数组内的数据进行增删查改分页 没调什么样式&#xff0c;不想写后端&#xff0c;当做练习 <template><div><!-- 查询 --><el-form :inline"true" :model"formQuery">&l…

高性能 MySQL 第四版(GPT 重译)(一)

前言 由 Oracle 维护的官方文档为您提供了安装、配置和与 MySQL 交互所需的知识。本书作为该文档的伴侣&#xff0c;帮助您了解如何最好地利用 MySQL 作为强大的数据平台来满足您的用例需求。 本版还扩展了合规性和安全性在操作数据库足迹中的日益重要作用。隐私法律和数据主…

使用Java版工程行业管理系统源码,提升工程项目的综合管理能力

工程项目管理涉及众多环节和角色&#xff0c;如何实现高效协同和信息共享是关键。本文将介绍一个采用先进技术框架的Java版工程项目管理系统&#xff0c;该系统支持前后端分离&#xff0c;功能全面&#xff0c;可满足不同角色的需求。从项目进度图表到施工地图&#xff0c;再到…

Java------数据结构之栈与队列(简单讲解)

本篇碎碎念&#xff1a;时隔n个月&#xff0c;继续写博客&#xff0c;假期落下的进度&#xff0c;在开学后努力追赶&#xff0c;假期不努力&#xff0c;开学徒伤悲啊&#xff0c;此时此刻真想对自己说一句&#xff0c;活该啊~~~~ 欠下的链表练习题讲解会在下次更新~~~~ 今日份励…

Ubuntu20.04 安装fcitx5输入法

序 ubuntu 20.04.3下fcitx5 需要从flatpak安装&#xff0c;&#xff08;由于qt版本&#xff0c;fcitx5-config只能安装在20.10上&#xff09;&#xff0c;中间出了各种问题&#xff0c;最后发现以下解决方案最好&#xff1a; 安装flatpak (建议使用官方ppa,版本较新) 1 2 3 …

视频素材库网站下载的地方在哪里?

视频素材库网站下载的地方在哪里&#xff1f;这是很多短视频创作者都会遇到的问题。别着急&#xff0c;今天我就来给大家介绍几个视频素材库网站下载的好去处&#xff0c;让你的视频创作更加轻松有趣&#xff01; 蛙学网&#xff1a;视频素材库网站下载的一定要选择蛙学网啦&am…

C++利用开散列哈希表封装unordered_set,unordered_map

C利用开散列哈希表封装unordered_set,unordered_map 一.前言1.开散列的哈希表完整代码 二.模板参数1.HashNode的改造2.封装unordered_set和unordered_map的第一步1.unordered_set2.unordered_map 3.HashTable 三.string的哈希函数的模板特化四.迭代器类1.operator运算符重载1.动…

【计算机考研】杭电 vs 浙工大 怎么选?

想求稳上岸的话&#xff0c;其他几所学校也可以考虑&#xff0c;以留在本地工作的角度考虑&#xff0c;这几所学校都能满足你的需求。 如果之后想谋求一份好工作&#xff0c;肯定优先杭电是比较稳的&#xff0c;当然复习的时候也得加把劲。 这个也可以酌情考虑&#xff0c;报…

C# 设置AutoScroll为true没效果的原因分析和解决办法

C#中添加tabControl 分页&#xff0c;将autoscroll设置为true发现缩小窗口没有滚动条效果。该问题出现后&#xff0c;检索发现也有很多人询问了该问题&#xff0c;但是都没有给出解决方案。 原因是内部button的属性Anchor设置为top、left、right、bottom导致的缩小界面窗口也没…

为什么Hashtable不允许插入nuIl键和null值?

1、典型回答 浅层次的来回答这个问题的答案是&#xff0c;JDK 源码不支持 Hashtable 插入 value 值为 null&#xff0c;如以下 JDK 源码所示&#xff1a; 也就是 JDK 源码规定了&#xff0c;如果你给 Hashtable 插入 value 值为 null 就会抛出空指针异常。 并且看上面的 JDK …

【Ubuntu】FTP站点搭建

配置顺序 前提条件&#xff1a;确保软件仓库可以正常使用&#xff0c;确保已正常配置IP地址 1.安装FTP服务 2.编辑FTP配置文件 3.设置开机自启 4.创建用户 5.配置用户限制名单 6.重启服务 7.查看运行状态 8.测试在同一局域网下的Windows查看文件 1.安装FTP服务 sudo apt insta…

【STM32嵌入式系统设计与开发】——8usart(串口通讯实验)

这里写目录标题 一、任务描述二、任务实施1、ActiveBeep工程文件夹创建2、函数编辑&#xff08;1&#xff09;主函数编辑&#xff08;2&#xff09;USART1初始化函数(usart1_init())&#xff08;3&#xff09;USART数据发送函数&#xff08; USART1_Send_Data&#xff08;&…

Tempo Talents | 创新专业建设方案,赋能高校4+N大数据学科人才培养

数字经济成为国家战略&#xff0c;是新一轮的经济发展引擎&#xff0c;数字人才、复合型人才成为发展的关键和核心要素。各级政府、区域开始以区域产业为导向&#xff0c;培育、聚集产业所需的数智化人才。 高校作为人才培养的重要基地&#xff0c;也发挥着不可或缺的作用。他…

Linux进程控制(一)

一、fork函数 在linux中&#xff0c;父进程通过fork函数创建子进程&#xff0c;子进程返回0&#xff0c;父进程返回子进程的pid&#xff0c;出现错误返回-1。 当运行fork函数时&#xff0c;OS会为子进程创建task_struct、mm_struct&#xff08;进程地址空间&#xff09;、页表&…

C语言实现高精度计时和高精度延时微秒级别

C语言实现高精度计时和高精度延时微秒级别 目的说明环境说明一、高精度延时(微秒级别)二、测试例程三、测试结果 目的说明 在Windows下C语言实现高精度计时功能和高精度延时微秒级别环境说明 Dev-C V5.11一、高精度延时(微秒级别) void vDelayUS(u32 usDelay) {LARGE_INTEGER…

C语言例:表达式10<<3+1的值

10的二进制 00001010 10<<3 01010000 十制左移m位&#xff0c;乘以。 0101 0000 十进制80 10<<31 81

Day75:WEB攻防-验证码安全篇接口滥用识别插件复用绕过宏命令填入滑块类

目录 图片验证码-识别插件-登录爆破&接口枚举 登录爆破 接口枚举 图片验证码-重复使用-某APP短信接口滥用 滑块验证码-宏命令-某Token&Sign&滑块案例 知识点&#xff1a; 1、验证码简单机制-验证码过于简单可爆破 2、验证码重复使用-验证码验证机制可绕过 3、…