- 该文档主要记录下 WebSocket 的基础封装配置,封装方法可以通用,部分配置基于
Vue3,可自行修改相应逻辑
import type { App } from 'vue';
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;
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;
}
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;
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.provide('socket', socket);
}
};
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);
socketObj?.onOpen(() => {});
socketObj?.onClose(() => {});
socketObj?.onError(() => {});
});
socketObj.send("自定义要发送的信息");
onBeforeUnmount(() => {
socketObj?.disconnect();
});
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,
};
};
import { useSocket, dataTreating } from "./useSocket";
const messageCallback = (event: any) => {
dataTreating(event).then((res: any) => {
});
};
const { socketObj } = useSocket(
"url",
messageCallback,
socketParams,
() => {}
);
socketObj.send("自定义要发送的信息");
socketObj?.onOpen("自定义方法");
socketObj?.onClose("自定义方法");
socketObj?.onError("自定义方法");