用了那么多年的WebSocket尽然发现断线重连后不会收到消息

实现一个健壮的WebSocket连接管理器

在现代Web应用中,实时通信变得越来越重要。WebSocket作为一种全双工通信协议,为前端应用提供了强大的实时数据交互能力。本文将介绍如何实现一个功能完善的WebSocket连接管理器,包含自动重连、心跳检测等关键特性。

WebSocket管理器的核心功能

实现的useWebSocket函数提供了以下核心功能:

  1. 自动连接:初始化时自动建立WebSocket连接
  2. 事件监听:通过事件机制处理消息、连接状态变化
  3. 心跳检测:定期发送心跳包保持连接活跃
  4. 自动重连:连接断开时自动尝试重新连接
  5. 手动控制:提供手动关闭连接的接口

实现解析

初始化与连接建立

js 复制代码
// 生成 digits 位随机数
const randomNumber = (digits = 8) =>{
    const min = Math.pow(10, digits - 1); // 10^(digits-1) 例如 8 位数最小是 10000000
    const max = Math.pow(10, digits) - 1; // 10^digits - 1 例如 8 位数最大是 99999999
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
export const useWebSocket = ({url = null, content, time = 10, heartbeat = 10, protocols = null}) => {
    const info = {
        // 存储各种状态和配置
        heartbeatInterval: null,
        time: time || 10,          // 重连间隔(秒)
        heartbeat: heartbeat || 10, // 心跳间隔(秒)
        TIMEID: null,              // 重连定时器ID
        socket: null,              // WebSocket实例
        protocols: protocols || null,
        url: url || null,
        content: content || 'ping',
        eventTarget: new EventTarget(), // 事件系统
        isManuallyClosed: false,  // 是否手动关闭
        isConnected: false         // 连接状态
    }
    
    const initWebSocket = () => {
        if (info.isManuallyClosed) return;
        
        info.socket?.close();
        info.socket = null;
        
        const protocol = location.protocol === 'https' ? 'wss' : 'ws';
        // 根据实际需求可以在后面拼接随机数
        const adder = info.url || import.meta.env.VITE_SOKET_URL;
        info.socket = info.protocols 
            ? new WebSocket(`${protocol}://${adder}`, info.protocols) 
            : new WebSocket(`${protocol}://${adder}`);
            
        setupEventHandlers();
    }
}

事件处理

js 复制代码
const setupEventHandlers = () => {
    // 连接成功
    info.socket.onopen = () => {
        info.eventTarget.dispatchEvent(new CustomEvent('open', {detail: "onopen"}));
        info.isConnected = true;
        send(info.content);
        startHeartbeat();
    }
    
    // 接收消息
    info.socket.onmessage = (evt) => {
        info.eventTarget.dispatchEvent(new CustomEvent('message', {detail: evt.data}));
    }
    
    // 连接关闭
    info.socket.onclose = (e) => {
        info.isConnected = false;
        info.eventTarget.dispatchEvent(new CustomEvent('close', {detail: e}));
        if (!info.isManuallyClosed) attemptReconnect();
    }
    
    // 连接错误
    info.socket.onerror = (e) => {
        info.isConnected = false;
        info.eventTarget.dispatchEvent(new CustomEvent('error', {detail: e}));
        attemptReconnect();
    }
}

心跳机制

js 复制代码
// 开始心跳检测
const startHeartbeat = () => {
    stopHeartbeat();
    info.heartbeatInterval = setInterval(
        () => send(info.content), 
        info.heartbeat * 1000
    );
}

// 停止心跳检测
const stopHeartbeat = () => {
    clearInterval(info.heartbeatInterval);
    info.heartbeatInterval = null;
};

自动重连机制

js 复制代码
// 尝试重新连接
const attemptReconnect = () => {
    stopHeartbeat();
    clearTimeout(info.TIMEID);
    info.TIMEID = setTimeout(initWebSocket, info.time * 1000);
}

公共API

js 复制代码
return {
    // 发送消息
    send: (msg) => info.socket?.send(msg),
    
    // 监听事件
    on: (event, handler) => info.eventTarget?.addEventListener(event, handler),
    
    // 关闭连接
    close: (code = 1000, msg = '正常手动关闭') => {
        info.isManuallyClosed = true;
        clearTimeout(info.TIMEID);
        stopHeartbeat();
        info.socket?.close(code, msg);
        info.socket = null;
        info.isConnected = false;
        removeEventListeners();
    }
}

使用示例

js 复制代码
// 创建WebSocket连接
const ws = useWebSocket({
    url: '192.168.3.21:9001/websoket/user',
    time: 5,       // 5秒重连间隔
    heartbeat: 15  // 15秒心跳间隔
});

// 监听消息
ws.on('message', (event) => {// 断线重连后收到消息依旧会触发
    console.log('收到消息:', event.detail);
});

// 监听连接打开
ws.on('open', () => {
    console.log('连接已建立');
});

// 监听连接关闭
ws.on('close', () => {
    console.log('连接已关闭');
});

// 发送消息
ws.send('Hello WebSocket!');

// 手动关闭连接
ws.close();
相关推荐
再学一点就睡6 分钟前
双 Token 认证机制:从原理到实践的完整实现
前端·javascript·后端
wallflower20208 分钟前
滑动窗口算法在前端开发中的探索与应用
前端·算法
蚂蚁绊大象8 分钟前
flutter第二话题-布局约束
前端
龙在天10 分钟前
我是前端,scss颜色函数你用过吗?
前端
Mapmost17 分钟前
单体化解锁3DGS场景深层交互价值,让3DGS模型真正被用起来!
前端
幻灵尔依1 小时前
前端编码统一规范
javascript·vue.js·代码规范
欢脱的小猴子1 小时前
VUE3加载cesium,导入czml的星座后页面卡死BUG 修复
前端·vue.js·bug
高级测试工程师欧阳1 小时前
CSS 基础概念
前端·css·css3
前端小巷子1 小时前
JS 实现图片瀑布流布局
前端·javascript·面试
Juchecar1 小时前
AI教你常识之 npm / pnpm / package.json
前端