WebSocket 前端使用vue3+ts+elementplus 实现连接

1.配置连接
websocket.ts文件如下

import { ElMessage } from "element-plus";interface WebSocketProps {url: string; // websocket地址heartTime?: number; // 心跳时间间隔,默认为 50000 msheartMsg?: string; // 心跳信息,默认为'ping'reconnectCount?: number; // 重连次数,默认为 5reconnectTime?: number; // 重连时间间隔,默认为 10000 msmessage: (ev: MessageEvent) => any; // 接收消息的回调open?: (ev: Event) => any; // 连接成功的回调close?: (ev: CloseEvent) => any; // 关闭的回调error?: (ev: Event) => any; // 错误的回调
}// webSocket 对象
let webSocket: WebSocket | null = null;
// webSocket定时器id
let setIntervalId: NodeJS.Timeout | null = null;export const initWebSocket = (config: WebSocketProps) => {if (typeof WebSocket === "undefined") {ElMessage.error("您的浏览器不支持Websocket通信协议,请使用Chrome或者其他高版本的浏览器!");return;}if (webSocket != null && webSocket.readyState === webSocket.OPEN) {return webSocket;}createWebSocket(config);return webSocket;
};/*** 创建WebSocket* @param config*/
const createWebSocket = (config: WebSocketProps) => {// 初始化 WebSocketwebSocket = new WebSocket(config.url);webSocket.onopen = (ev: Event) => {config.open && config.open(ev);/*** 发送心跳* 使用Nginx代理WebSocket的时候,客户端与服务器握手成功后,如果在60秒内没有数据交互,就会自动断开连接。* Nginx默认的断开链接时间为60秒*/sendPing(config.heartTime ?? 50000, config.heartMsg ?? "ping");};webSocket.onmessage = (ev: MessageEvent) => config.message(ev);webSocket.onerror = (ev: Event) => error(config, ev);webSocket.onclose = (ev: CloseEvent) => close(config, ev);
};/*** 发送心跳* @param {number} heartTime 心跳间隔毫秒 默认50000* @param {string} heartMsg 心跳名称 默认字符串ping*/
const sendPing = (heartTime: number, heartMsg: string) => {webSocket?.send(heartMsg);setIntervalId = setInterval(() => {webSocket?.send(heartMsg);}, heartTime);
};/*** WebSocket 关闭的回调方法* @param config*/
const close = (config: WebSocketProps, ev: CloseEvent) => {config.close && config.close(ev);clearInterval(Number(setIntervalId));
};let falg = false;
// 重连次数
let reconnectCount = 0;
// 重连定时器id
let reconnectId: NodeJS.Timeout | null = null;/*** WebSocket 关闭的回调方法* @param config*/
const error = (config: WebSocketProps, ev: Event) => {config.error && config.error(ev);if (falg) return;reconnectId = setInterval(() => {falg = true;reconnectCount++;console.log("正在重新连接,次数:" + reconnectCount);let socket = initWebSocket(config);if (socket?.readyState === socket?.OPEN) {reconnectCount = 0;falg = false;clearInterval(Number(reconnectId));}if (reconnectCount >= 5) {clearInterval(Number(reconnectId));}}, config.reconnectTime ?? 10000);
};

2. 创建链接
新建 websocket.vue文件

<template><div></div>
</template><script setup lang="ts" name="WebSocket">
import { useUserStore } from "@/stores/modules/user";
import { DEV_WS_URL_HEAD, DEV_WS_URL_TAIL, PRO_WS_URL_HEAD, PRO_WS_URL_TAIL } from "@/api/config/websocketUrl";
import { WebSocketMsg, EventKeyEnum } from "@/api/interface/webSocketMsg/index";
import { initWebSocket } from "@/utils/websocket";
import { ElMessageBox, ElNotification } from "element-plus";
import mittBus from "@/utils/mittBus";
import { LOGIN_URL } from "@/config";//export const LOGIN_URL: string = "/login";这是登录的路径
const userStore = useUserStore();//   userStore.setToken(data.tokenValue);登录的时候存 token
const router = useRouter();
const webSocket = initWebSocket({url:(import.meta.env.VITE_WS_FLAG == "production" ? PRO_WS_URL_HEAD + PRO_WS_URL_TAIL : DEV_WS_URL_HEAD + DEV_WS_URL_TAIL) +"/webSocketService/" +userStore.token,open: () => {console.info("连接WebSocket成功");},message: (event: MessageEvent) => {const webSocketMsg: WebSocketMsg = JSON.parse(event.data);console.log("[webSocketMsg] data: " + event.data);switch (webSocketMsg.eventKey) {case EventKeyEnum.CONNECTION_SUCCESS:mittBus.emit("init_seat");break;case EventKeyEnum.MSG_COMMON:mittBus.emit(EventKeyEnum.MSG_COMMON, event.data);break;case EventKeyEnum.SATOKEN:mittBus.emit(EventKeyEnum.SATOKEN, event.data);break;}},close: () => {console.log("close");},error: () => {console.log("error");}
});userStore.setWebSocket(webSocket ?? null);
// 后端推送消息,执行相关操作
mittBus.on(EventKeyEnum.SATOKEN, (val: any) => {let msgData = JSON.parse(val);let eventKey = msgData.eventKey;let msgContent = msgData.msgContent;// 清除 TokenuserStore.setToken("");// 清除用户信息userStore.setUserInfo("");// 清除所有数据userStore?.webSocket?.close();userStore.setWebSocket(null);// 3.重定向到登陆页router.replace(LOGIN_URL);if (eventKey == "SATOKEN") {ElMessageBox.confirm(msgContent, "提示", {confirmButtonText: "确认",type: "error",showCancelButton: false});}// 当页面关闭的时候,去销毁这个事务线程 ---> 解决mitt多次触发mittBus.all.delete(EventKeyEnum.SATOKEN);
});
mittBus.on(EventKeyEnum.MSG_COMMON, (val: any) => {let msgData = JSON.parse(val);let eventKey = msgData.eventKey;let msgContent = msgData.msgContent;let sendTime = msgData.sendTime;if (eventKey == "MSG_COMMON") {ElNotification({title: "管理员消息",dangerouslyUseHTMLString: true,position: "bottom-right",duration: 0,customClass: "msg",message: `<span style="color:gray">${sendTime}<span><br/><pre>${msgContent}</pre>`});}// 当页面关闭的时候,去销毁这个事务线程 ---> 解决mitt多次触发// mittBus.all.delete(EventKeyEnum.MSG_COMMON);
});
</script><style scoped lang="scss"></style>

下面的文件都是上面第二步用到的文件
引用到的 user 文件

import { defineStore } from "pinia";
import { UserState } from "@/stores/interface";
//UserState用到的类型如下
//export interface UserState {token: string;tokenName: string;userInfo: any;webSocket: WebSocket | null;
}import piniaPersistConfig from "@/stores/helper/persist";export const useUserStore = defineStore({id: "geeker-user",state: (): UserState => ({token: "",tokenName: "",userInfo: "",webSocket: null}),getters: {},actions: {// Set TokensetToken(token: string) {this.token = token;},setTokenName(tokenName: string) {this.tokenName = tokenName;},// Set setUserInfosetUserInfo(userInfo: any) {this.userInfo = userInfo;},// setWebSocketsetWebSocket(webSocket: WebSocket | null) {this.webSocket = webSocket;}},persist: piniaPersistConfig("geeker-user")
});

持久化文件 pinia
persist.ts

import { PersistedStateOptions } from "pinia-plugin-persistedstate";/*** @description pinia 持久化参数配置* @param {String} key 存储到持久化的 name* @param {Array} paths 需要持久化的 state name* @return persist* */
const piniaPersistConfig = (key: string, paths?: string[]) => {const persist: PersistedStateOptions = {key,storage: localStorage,// storage: sessionStorage,paths};return persist;
};export default piniaPersistConfig;

websocketUrl文件
websocketUrl.ts

/*** 连接WebSocket服务地址的网关IP端口 -- 开发环境* (解决扫描漏洞:IP地址泄露)*/// 头部
//示例"ws://199.166.0."
export const DEV_WS_URL_HEAD = "";// 尾部
//示例"11:1111"
export const DEV_WS_URL_TAIL = "";/*** 连接WebSocket服务地址的网关IP端口 -- 正式环境* (解决扫描漏洞:IP地址泄露)*/// 头部
//示例"ws://00.111."
export const PRO_WS_URL_HEAD = "";// 尾部
//示例"111.11:1111"
export const PRO_WS_URL_TAIL = "";

@/api/interface/webSocketMsg/index.ts 文件如下

/*** WebSocket 消息类型*/
export interface WebSocketMsg {/*** 事件标识**/eventKey: EventKeyEnum | "";/*** 用户id**/userId: string;/*** 用户所属团队id**/userTeamId?: string;/*** 用户token**/token?: string;/*** 消息内容***/msgContent: string;/*** 消息发送时间(yyyy-MM-dd HH:mm:ss)***/sendTime: string;/*** 是否发送给所有人***/everyone: boolean;
}export enum EventKeyEnum {/*** WebSocket连接成功标识,根据后台定义*/CONNECTION_SUCCESS = "",/*** 提醒消息推送*/MSG_COMMON = "",/*** 用户登录认证相关消息*/SATOKEN = ""
}

mitt 使用
mittBus.ts文件

import mitt from "mitt";const mittBus = mitt();export default mittBus;

番外
在响应拦截器要关闭连接
在这里插入图片描述
在这里插入图片描述
退出登录也关闭连接
在这里插入图片描述
在框架main 文件引入
在这里插入图片描述
动态路由也要关闭
在这里插入图片描述

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

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

相关文章

TCP 重传、滑动窗口、流量控制、拥塞控制

1&#xff1a;重传机制 超时重传 快速重传 SACK 方法 Duplicate SACK 1&#xff1a;重传机制 超时重传&#xff1a;重传机制的其中一个方式&#xff0c;就是在发送数据时&#xff0c;设定一个定时器&#xff0c;当超过指定的时间后&#xff0c;没有收到对方的ACK确认应答报文…

java:springboot3集成swagger(springdoc-openapi-starter-webmvc-ui)

背景 网上集成 swagger 很多都是 Springfox 那个版本的&#xff0c;但是那个版本已经不更新了&#xff0c;springboot3 集成会报错 Typejavax.servlet.http.HttpServletRequest not present&#xff0c;我尝试了很多才知道现在用 Springdoc 了&#xff0c;今天我们来入门一下 …

OCR原理解析

目录 1.概述 2.应用场景 3.发展历史 4.基于传统算法的OCR技术原理 4.1 图像预处理 4.1.1 灰度化 4.1.2 二值化 4.1.3 去噪 4.1.4 倾斜检测与校正 4.1.4.2 轮廓矫正 4.1.5 透视矫正 4.2 版面分析 4.2.1 连通域检测文本 4.2.2 MSER检测文本 4.3 字符切割 4.3.1 连…

TiDB 在咪咕云原生场景下的实践

导读 咪咕是中国移动旗下的视频科技公司&#xff0c;门户系统是其核心业务之一。 为满足用户的多样化需求&#xff0c;咪咕计划对其数据库进行升级。 经过对中国主流国产数据库的测试评估后&#xff0c;咪咕选择了 TiDB&#xff0c;并成功将其落地于门户系统云化项目。 TiDB 为…

Linux系统之centos7编译安装Python 3.8

前言 CentOS (Community Enterprise Operating System) 是一种基于 Red Hat Enterprise Linux (RHEL) 进行源代码再编译并免费提供给用户的 Linux 操作系统。 CentOS 7 采用了最新的技术和软件包&#xff0c;并提供了强大的功能和稳定性。它适用于各种服务器和工作站应用场景&a…

分布式架构demo

1、外层创建pom 版本管理器 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.15</version><relativePath/> <!-- lookup parent from repository…

鉴源实验室 | 汽车网络安全攻击实例解析(三)

作者 | 张璇 上海控安可信软件创新研究院工控网络安全组 来源 | 鉴源实验室 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 引言&#xff1a;随着现代汽车技术的迅速发展&#xff0c;车辆的进入和启动方式经历了显著的演变。传统的物理钥匙逐渐被无钥匙进…

certbot—30秒部署你的HTTPS,永久免费,自动续约

在之前我已经介绍过部署反向代理的2种方式了。第一种是通过宝塔的反向代理配置然后开启HTTPS。 第二种是通过nginxproxymanager。 今天要给大家分享的是一个 certbot。 Certbot 是一个由 Lets Encrypt 开发的免费开源工具&#xff0c;用于自动化部署和管理 SSL/TLS 证书。它具有…

SpringBoot3.x + mp代码生成器(更新系列)

小伙伴们&#xff0c;有没有这样一个体验&#xff0c;每次开始写一个项目时&#xff0c;搭建项目环境&#xff0c;建entity&#xff0c;mapper&#xff0c;service&#xff0c;controller层文件的感到繁琐&#xff0c;这属实体力活呀&#xff01;然而&#xff0c;自从有了Mybat…

【二分查找】LeetCode1970:你能穿过矩阵的最后一天

本文涉及的基础知识点 二分查找算法合集 作者推荐 动态规划LeetCode2552&#xff1a;优化了6版的1324模式 题目 给你一个下标从 1 开始的二进制矩阵&#xff0c;其中 0 表示陆地&#xff0c;1 表示水域。同时给你 row 和 col 分别表示矩阵中行和列的数目。 一开始在第 0 …

【开源】基于JAVA的大病保险管理系统

项目编号&#xff1a; S 031 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S031&#xff0c;文末获取源码。} 项目编号&#xff1a;S031&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统配置维护2.2 系统参保管理2.3 大…

uniapp是否可以用elementUI等前端UI库、使用步骤以及需要注意的问题

文章目录 uniapp是否可以用elementUI等前端UI库使用方法和步骤问题如何解决 uniapp是否可以用elementUI等前端UI库 在PC端开发uniapp&#xff0c;可以用elementUI&#xff0c;因为elementUI就是PC端的。 在使用uniapp&#xff0c;选择vue2.0时&#xff0c;实测可以用nodejs16的…

java企业财务管理系统springboot+jsp

1、基本内容 &#xff08;1&#xff09;搭建基础环境&#xff0c;下载JDK、开发工具eclipse/idea。 &#xff08;2&#xff09;通过HTML/CSS/JS搭建前端框架。 &#xff08;3&#xff09;下载MySql数据库&#xff0c;设计数据库表&#xff0c;用于存储系统数据。 &#xff08;4…

三、使用CRT连接三台虚拟机

目录 1、建立连接 2、参数配置 3、设置主题,颜色和仿真 1、建立连接

SQL server 2016安装

1、关系数据库的基本概念。 行&#xff1a;每行成为一条“记录”或“元组”&#xff0c;用于描述一个对象的信息。 列&#xff1a;每列称为一个“字段”或“属性”&#xff0c;用于描述对象的一个属性。 2、主键与外键。 主键&#xff1a;键&#xff0c;即关键字。主键由一个或…

Android--Jetpack--Lifecycle详解

富贵本无根&#xff0c;尽从勤里得 一&#xff0c;定义 Lifecycle 是一个具备宿主生命周期感知能力的组件。它持有组件&#xff08;Activity/Fragment&#xff09;生命周期状态信息&#xff0c;并且允许其观察者监听宿主生命周期状态变化。 顾名思义&#xff0c;Lifecycle的主…

TA-Lib学习研究笔记(八)——Momentum Indicators 上

TA-Lib学习研究笔记&#xff08;八&#xff09;——Momentum Indicators 上 Momentum Indicators 动量指标&#xff0c;是最重要的股票分析指标&#xff0c;能够通过数据量化分析价格、成交量&#xff0c;预测股票走势和强度&#xff0c;大部分指标都在股票软件中提供。 1. A…

水利安全监测方案——基于RTU200的解决方案

引言&#xff1a; 水资源是人类赖以生存的重要基础&#xff0c;对于保障水利系统安全运行以及应对自然灾害起着关键作用。为了实现水利安全监测的目标&#xff0c;我们提出了基于RTU200的解决方案。本方案将结合RTU200的可靠性、灵活性和高效性&#xff0c;为您打造一个全面的…

[笔记]dubbo发送接收

公司需要使用java技术栈接入一套自定义的通讯协议&#xff0c;所以参考下dubbo的实现原理。 consumer 主要使用ThreadlessExecutor实现全consumer的全双工通讯。consumer创建本次请求的requestId用于将response和request匹配。 然后分以下几步完成一次请求发送并接收结果&…

Elasticsearch分词器--空格分词器(whitespace analyzer)

介绍 文本分析&#xff0c;是将全文本转换为一系列单词的过程&#xff0c;也叫分词。analysis是通过analyzer(分词器)来实现的&#xff0c;可以使用Elasticearch内置的分词器&#xff0c;也可以自己去定制一些分词器。除了在数据写入时将词条进行转换&#xff0c;那么在查询的时…