1.配置连接 websocket.ts文件如下
import { ElMessage } from "element-plus";
interface WebSocketProps {
url: string; // websocket地址
heartTime?: number; // 心跳时间间隔,默认为 50000 ms
heartMsg?: string; // 心跳信息,默认为'ping'
reconnectCount?: number; // 重连次数,默认为 5
reconnectTime?: number; // 重连时间间隔,默认为 10000 ms
message: (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) => {
// 初始化 WebSocket
webSocket = 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文件
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;
// 清除 Token
userStore.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: `${sendTime}${msgContent}
`
});
}
// 当页面关闭的时候,去销毁这个事务线程 ---> 解决mitt多次触发
// mittBus.all.delete(EventKeyEnum.MSG_COMMON);
});
下面的文件都是上面第二步用到的文件 引用到的 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 Token
setToken(token: string) {
this.token = token;
},
setTokenName(tokenName: string) {
this.tokenName = tokenName;
},
// Set setUserInfo
setUserInfo(userInfo: any) {
this.userInfo = userInfo;
},
// setWebSocket
setWebSocket(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 文件引入 动态路由也要关闭
推荐链接
大家都在找:
websocket:websocket服务未连接怎么办
前端:前端开发需要学什么
网络协议:网络协议是什么
发表评论
2024-07-02 11:44:27回复
1. **网络问题** :请检查你的网络连接是否正常,以及服务器是否已经启动并可以接受连接。
2. **跨域问题** :如果你的网页和服务器不在同一域名下,可能会因为浏览器的同源策略而无法建立WebSocket连接,你需要确保服务器设置了正确的CORS(跨源资源共享)策略,允许你的网页域名进行跨域访问。
3. **端口问题** :请检查你的代码中WebSocket的URL是否正确,包括协议、主机名、端口号等信息。
4. **浏览器兼容性问题** :虽然现代浏览器对WebSocket的支持非常好,但在一些较旧的浏览器或特定的浏览器模式(如无痕浏览、隐私模式等)下,可能无法使用WebSocket,你可以尝试在其他浏览器或不同的浏览器模式下测试你的代码。
5. **服务器端问题** :如果服务器端没有正确处理WebSocket的连接请求,或者在处理过程中出现了错误,也可能导致WebSocket的状态为CLOSED,你需要检查服务器端的日志,看是否有关于WebSocket错误的记录。
2024-06-25 21:16:49回复
2024-06-25 21:14:49回复
1. 网络问题:请检查您的网络连接是否正常,尝试重新连接网络。
2. 服务器问题:请检查您的服务器是否正常运行,以及WebSocket服务是否已启动。
3. 代码问题:请检查您的代码中是否有错误,例如在创建WebSocket对象时传入了错误的参数。
4. 浏览器兼容性问题:请确保您使用的浏览器支持WebSocket协议。
5. 跨域问题:如果您的WebSocket服务和前端页面不在同一个域名下,可能会遇到跨域问题,请检查您的服务器是否已配置允许跨域访问。