| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- // WebSocket 工具类
- type MessageCallback = (message: string) => void;
- type ErrorCallback = (error: Event) => void;
- let ws: WebSocket | null = null;
- let reconnectTimer: NodeJS.Timeout | null = null;
- let heartbeatTimer: NodeJS.Timeout | null = null;
- let reconnectAttempts = 0;
- const maxReconnectAttempts = 5;
- const reconnectDelay = 3000; // 3秒
- const heartbeatInterval = 30000; // 30秒心跳
- /**
- * 连接 WebSocket
- * @param url WebSocket 地址
- * @param params 连接参数(会作为查询参数)
- * @param onMessage 消息回调
- * @param onError 错误回调
- */
- export const connectWebsocket = (
- url: string,
- params: Record<string, any> = {},
- onMessage: MessageCallback,
- onError?: ErrorCallback
- ) => {
- // 如果已经连接,先关闭
- if (ws && ws.readyState === WebSocket.OPEN) {
- closeWebsocket();
- }
- // 构建带参数的 URL
- const paramString = new URLSearchParams(params).toString();
- const fullUrl = paramString ? `${url}?${paramString}` : url;
- try {
- ws = new WebSocket(fullUrl);
- ws.onopen = () => {
- console.log('WebSocket 连接成功');
- reconnectAttempts = 0;
-
- // 启动心跳
- startHeartbeat();
- };
- ws.onmessage = (event) => {
- const message = event.data;
-
- // 处理心跳消息
- if (message === 'heartbeat' || message === 'ping') {
- // 响应心跳
- if (ws && ws.readyState === WebSocket.OPEN) {
- ws.send('pong');
- }
- return;
- }
- // 调用消息回调
- onMessage(message);
- };
- ws.onerror = (error) => {
- console.error('WebSocket 错误:', error);
- if (onError) {
- onError(error);
- }
- };
- ws.onclose = () => {
- console.log('WebSocket 连接关闭');
- stopHeartbeat();
-
- // 尝试重连
- if (reconnectAttempts < maxReconnectAttempts) {
- reconnectAttempts++;
- console.log(`尝试重连 (${reconnectAttempts}/${maxReconnectAttempts})...`);
- reconnectTimer = setTimeout(() => {
- connectWebsocket(url, params, onMessage, onError);
- }, reconnectDelay);
- } else {
- console.error('WebSocket 重连次数已达上限,停止重连');
- }
- };
- } catch (error) {
- console.error('WebSocket 连接失败:', error);
- if (onError) {
- onError(error as Event);
- }
- }
- };
- /**
- * 关闭 WebSocket 连接
- */
- export const closeWebsocket = () => {
- if (reconnectTimer) {
- clearTimeout(reconnectTimer);
- reconnectTimer = null;
- }
-
- stopHeartbeat();
-
- if (ws) {
- ws.onopen = null;
- ws.onmessage = null;
- ws.onerror = null;
- ws.onclose = null;
-
- if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
- ws.close();
- }
-
- ws = null;
- }
-
- reconnectAttempts = 0;
- console.log('WebSocket 已关闭');
- };
- /**
- * 启动心跳
- */
- const startHeartbeat = () => {
- stopHeartbeat();
-
- heartbeatTimer = setInterval(() => {
- if (ws && ws.readyState === WebSocket.OPEN) {
- ws.send('heartbeat');
- }
- }, heartbeatInterval);
- };
- /**
- * 停止心跳
- */
- const stopHeartbeat = () => {
- if (heartbeatTimer) {
- clearInterval(heartbeatTimer);
- heartbeatTimer = null;
- }
- };
- /**
- * 检查 WebSocket 连接状态
- */
- export const isWebSocketConnected = (): boolean => {
- return ws !== null && ws.readyState === WebSocket.OPEN;
- };
|