技术说明
1 webSock
一个可以动态注册消息回调函数功能的组件
1.1 代码
src\service\websoct.ts
js
import { baseUrlJoin, baseURL } from "@/service/base-url";
import SockJS from 'sockjs-client/dist/sockjs.min.js'
import Stomp from 'stompjs'
import _ from "lodash";
const BASE_WS = baseUrlJoin(baseURL, "ws");
const TOPIC = '/topic/broadcast'
const SENDMSG = '/app/sendMsg'
interface WebsoctBody {
type: string,
message: any
}
// 定义回调函数类型:带一个参数,参数类型可以根据实际需求调整
type Callback = (body: WebsoctBody, params?: any | null) => void;
interface CallbackItemType {
/**
* 回调函数
*/
callback: Callback,
/**
* 回调函数的类型标识,也就是标识的名称
*/
callbackType: string,
/**
* 消息类型,与WebsoctBody中的type字段对应
*/
type: string
}
// 定义回调函数字典,key与WebsoctBody中的type字段对应,value为回调函数信息数组
interface CallbackDic {
[type: string]: CallbackItem[];
}
class WebSoctService {
private socket: WebSocket | null = null;
private stompClient: Stomp.Client | null = null;
private callbackDic: CallbackDic = {}
private succesCallballs: Callback[] = []
// 重连相关参数
private reconnectDelay = 3000; // 重连间隔,单位毫秒
private maxReconnectAttempts = 10; // 最大重连次数
private reconnectAttempts = 0; // 当前重连次数
constructor() {
}
init() {
this.connect()
}
connect(succesCallball: Callback | null = null) {
if (succesCallball) {
this.succesCallballs.push(succesCallball)
}
if (!this.stompClient || !this.stompClient.connected) {
this.socket = new SockJS(BASE_WS);
this.stompClient = Stomp.over(this.socket);
this.stompClient.debug = () => { }; // 禁用日志
// 绑定断开事件,SockJS 实例支持 onclose
this.socket.onclose = (event) => {
console.warn('连接已断开,尝试重连...', event);
this.tryReconnect();
};
this.stompClient.connect(
{},
(frame: string) => {
console.log("Connected: " + frame);
// 重置重连计数
this.reconnectAttempts = 0;
// 订阅广播
this.stompClient?.subscribe(TOPIC, (response: { body: string; }) => {
const body: WebsoctBody = JSON.parse(response.body);
console.log(body);
if (body.type === "connet") {
console.log(body.message);
const cnt = this.succesCallballs.length
for (let i = 0; i < cnt; i++) {
this.succesCallballs.pop()(body)
}
}
if (body.type && Object.prototype.hasOwnProperty.call(this.callbackDic, body.type)) {
_.get(this.callbackDic, body.type, []).forEach((fun: CallbackItemType) => fun.callback(body));
}
});
this.send("connet", "消息服务连接成功");
},
(error: any) => {
// 连接失败时触发这里
console.error("连接失败,尝试重连:", error);
this.tryReconnect();
}
);
}
}
// 重连逻辑
tryReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
setTimeout(() => {
console.log(`第 ${this.reconnectAttempts} 次重连尝试...`);
this.connect();
}, this.reconnectDelay);
} else {
console.error("重连次数超过限制,停止重连");
}
}
tryToReconnect(maxReconnectAttempts: number, interval_secend: number, succesCallball: Callback) {
let count = 0
this.connect(succesCallball);
const interval = setInterval(() => {
count++;
console.log(`第 ${count} 次重连尝试...`);
succesCallball(null, maxReconnectAttempts - count)
this.connect()
if (count >= maxReconnectAttempts) {
clearInterval(interval);
}
}, interval_secend * 1000);
return interval
}
// 添加回调函数
addCallbackItem(callbackItem: CallbackItem) {
const type = callbackItem.type
if (!this.callbackDic[type]) {
this.callbackDic[type] = []
}
this.callbackDic[type].push(callbackItem)
return this
}
// 移除回调函数
remove(type: string, callbackType: string | "defualt") {
const callbackDics = _.get(this.callbackDic, type, [])
_.remove(callbackDics, (item: CallbackItemType) => item.callbackType === callbackType)
if (this.callbackDic[type].length) {
delete this.callbackDic[type]
}
}
// 发送消息
public send(type: string, message: any) {
const json = { type, message }
this.stompClient.send(SENDMSG, {}, JSON.stringify(json));
}
}
const webSoctService = new WebSoctService()
class CallbackItem implements CallbackItemType {
public type: string
public callbackType: string
public callback: Callback
constructor(type: string, callbackType: string) {
this.type = type
this.callbackType = callbackType
}
register(callback: Callback) {
this.callback = callback
webSoctService.addCallbackItem(this)
return webSoctService
}
remove() {
webSoctService.remove(this.type, this.callbackType)
}
}
const useWebSockt = (type: string, callbackType: string = "defualt"): CallbackItem => {
return new CallbackItem(type, callbackType)
}
export { webSoctService, useWebSockt }
1.2 说明
-
参数设置
-
BASE_WS:ws连接基础地址
-
TOPIC:指定接收主题,后端响应格式应为:
json{"type":"消息类型","message":"返回的信息,如json字符串"} -
SENDMSG:发送给后台的消息,格式
json{"type":"消息类型","message":"返回的信息,如json字符串"}
-
-
使用
-
首先初始化websock,在App.vue引入websoct.ts
jsimport { webSoctService } from "@/service/websoct"; onMounted(() => { webSoctService.init() }) -
在组件中使用
jsimport { useWebSockt } from "@/service/websoct"; // 1、useWebSockt const type = "LOG" // 这里是TOPIC后端响应的type const callbackType = "defualt" // 回调函数类型,对回调函数做识别 const useWebSockt = common.useWebSockt(type,callbackType); // 2、注册回调函数 useWebSockt.register((data) => { if (data.message) { // 回调函数操作 } }); // 3、注销回调函数(选用) useWebSockt.remove()
-