WebSocket 全局封装
- 该文档主要记录下 WebSocket 的基础封装配置,封装方法可以通用,部分配置基于
Vue3,可自行修改相应逻辑
配置文件
// webSocket.ts
import type { App } from 'vue';
// socket 自定义配置
interface configInfo {
reconnect: number; // 重连次数
reconnectAttempts: number; // 重连最大次数
reconnectInterval: number; // 重连间隔(毫秒)
reconnection: boolean; // 是否重连
autoConnect: boolean; // 创建时是否自动连接
heartbeatInterval: number; // 心跳间隔(毫秒)
}
const socketInfo: configInfo = {
reconnect: 0,
reconnectAttempts: 10,
reconnectInterval: 1000,
reconnection: true,
autoConnect: false,
heartbeatInterval: 2000
};
type CallbackFunction = (...args: any[]) => void;
// 回调data数据处理
export const dataTreating = (data: any) => {
return new Promise((resolve, reject) => {
resolve(data)
});
};
class WebSocketPlugin {
private url = '';
private socket: any = null;
private heartbeatIntervalId: any = null;
private openCallbacks: (() => void)[] = [];
private messageCallbacks: ((data: any) => void)[] = [];
private closeCallbacks: (() => void)[] = [];
private errorCallbacks: ((error: Event) => void)[] = [];
constructor(url: string = '', data = {}) {
if (!this.getToken()) {
return;
}
const socketUrl = "ws://" + window.location.host + "/ws";
this.url = url || socketUrl;
this.socket = null;
if (socketInfo.autoConnect) {
this.connect();
}
}
// 重连
private reconnectSocket = () => {
this.stopHeartbeat();
if (!this.getToken()) {
console.error('未登录,无法连接WebSocket');
socketInfo.reconnectAttempts = 0;
return;
}
if (this.isCloseSocket || this.connecting || this.isOpen()) {
return;
}
// 不自动重连 or 超出请求次数
if (!socketInfo.reconnection || socketInfo.reconnect >= socketInfo.reconnectAttempts) {
return;
}
socketInfo.reconnectAttempts += 1;
// 进行重连
setTimeout(() => {
this.connect();
}, socketInfo.reconnectInterval);
};
// 登录凭证
private getToken() {
return '';
}
// 是否正在连接
private connecting = false;
// 初始化连接
connect(cb?: CallbackFunction) {
if (!this.getToken()) {
console.error('未登录,无法连接WebSocket');
return;
}
if (this.connecting) {
return;
}
this.isCloseSocket = false;
this.connecting = true;
this.socket = new WebSocket(this.url);
// 连接成功
this.socket.onopen = () => {
this.connecting = false;
socketInfo.reconnect = 0;
this.startHeartbeat();
this.openCallbacks.forEach(callback => callback());
cb && cb();
};
// 接收消息
this.socket.onmessage = (event: any) => {
this.messageCallbacks.forEach(callback => callback(event));
};
// 关闭服务
this.socket.onclose = () => {
this.connecting = false;
this.reconnectSocket();
this.closeCallbacks.forEach(callback => callback());
};
// 连接错误
this.socket.onerror = (error: any) => {
this.connecting = false;
this.reconnectSocket();
this.errorCallbacks.forEach(callback => callback(error));
};
}
// 是否已连接
isOpen() {
return this.socket && this.socket.readyState === WebSocket.OPEN;
}
// 发送信息
send(data: any) {
return new Promise((resolve, reject) => {
if (this.isOpen()) {
this.socket.send(data);
resolve(true);
} else {
this.reconnectSocket();
reject(false);
}
});
}
// 定义心跳连接
private startHeartbeat() {
this.heartbeatIntervalId = setInterval(() => {
this.send(`PING:{timestamp:${new Date().getTime()}}`);
}, socketInfo.heartbeatInterval);
}
// 关闭心跳连接
private stopHeartbeat() {
clearInterval(this.heartbeatIntervalId);
}
// 手动关闭,不再重连
private isCloseSocket = false;
// 关闭 socket
disconnect() {
this.isCloseSocket = true;
if (this.socket) {
this.socket.close();
}
}
// 连接成功回调
onOpen(callback: () => void): void {
this.openCallbacks.push(callback);
}
// 数据返回回调
onMessage(callback: (data: any) => void): void {
this.messageCallbacks.push(callback);
}
// 关闭回调
onClose(callback: () => void): void {
this.closeCallbacks.push(callback);
}
// 报错回调
onError(callback: (error: Event) => void): void {
this.errorCallbacks.push(callback);
}
}
export { WebSocketPlugin };
export default {
install: (app: App, obj?: configInfo) => {
if (typeof WebSocket === 'undefined') {
console.log('浏览器不支持WebSocket');
return;
}
Object.assign(socketInfo, obj);
const socket = new WebSocketPlugin();
// 定义全局变量
// app.config.globalProperties.$socket = socket;
// 全局注入
app.provide('socket', socket);
}
};
使用
全局使用
// main.ts
import SocketIO from "./webSocket";
import App from "./App.vue";
const app = createApp(App);
app.use(SocketIO).mount("#app");
// 要调用的页面
import { dataTreating } from "./webSocket";
const socketObj: any = inject("socket");
// 回调信息处理
const messageCallback = (event: any) => {
dataTreating(event).then((res: any) => {
// 你的业务逻辑
});
};
onMounted(() => {
// 获取信息
socketObj?.onMessage(messageCallback);
// 以下内容为可选方法
// 连接成功事件,只会在重连 or 第一次连接的时候执行
socketObj?.onOpen(() => {});
// 关闭连接事件
socketObj?.onClose(() => {});
// 连接错误事件
socketObj?.onError(() => {});
});
// 发送
socketObj.send("自定义要发送的信息");
onBeforeUnmount(() => {
// 关闭连接,可选
socketObj?.disconnect();
});
自定义 hooks
// useSocket.ts
import { WebSocketPlugin, dataTreating } from "./webSocket";
export { dataTreating };
export const useSocket = (
url: string,
messageCallback: (data: any) => void,
socketParams: {
[key: string]: any,
} = {},
init?: () => void
) => {
const socketObj = new WebSocketPlugin(url, socketParams);
const initSuccess = ref(false);
onMounted(async () => {
socketObj?.onOpen(() => {
if (!initSuccess.value) {
initSuccess.value = true;
init && init();
}
});
socketObj?.onMessage((data: any) => {
messageCallback && messageCallback(data);
});
});
onBeforeUnmount(() => {
// 关闭连接
socketObj?.disconnect();
});
return {
socketObj,
};
};
- 自定义 webSocket 局部使用
import { useSocket, dataTreating } from "./useSocket";
// 回调信息处理
const messageCallback = (event: any) => {
dataTreating(event).then((res: any) => {
// 你的业务逻辑
});
};
const { socketObj } = useSocket(
// url 连接地址
"url",
// socket回调
messageCallback,
// 连接socket时的传值(可选)
socketParams,
// 成功连接后要执行的方法(可选)
() => {}
);
// 发送
socketObj.send("自定义要发送的信息");
// 以下内容为(可选方法)
// 连接成功事件,只会在重连 or 第一次连接的时候执行
socketObj?.onOpen("自定义方法");
// 关闭连接事件
socketObj?.onClose("自定义方法");
// 连接错误事件
socketObj?.onError("自定义方法");
Powered by Waline v2.15.8