WebSocket使用注意事项与优化策略

1. 连接稳定性问题

心跳机制

TypeScript 复制代码
// 必须实现心跳保活
let heartbeatInterval;
const HEARTBEAT_INTERVAL = 30000; // 30秒

function setupHeartbeat(ws) {
  heartbeatInterval = setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify({ type: 'ping' }));
    }
  }, HEARTBEAT_INTERVAL);
}

// 收到pong后重置超时计时器
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  if (data.type === 'pong') {
    // 重置超时计时器
  }
};

2. 重连机制

指数退避重连

TypeScript 复制代码
let reconnectAttempts = 0;
const MAX_RECONNECT_ATTEMPTS = 10;
const BASE_DELAY = 1000;

function reconnect() {
  if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
    console.error('Max reconnection attempts reached');
    return;
  }
  
  const delay = Math.min(BASE_DELAY * Math.pow(2, reconnectAttempts), 30000);
  reconnectAttempts++;
  
  setTimeout(() => {
    initWebSocket();
  }, delay);
}

ws.onclose = () => {
  clearInterval(heartbeatInterval);
  reconnect();
};

3. 消息顺序与并发控制

TypeScript 复制代码
// 消息队列处理
class WebSocketManager {
  constructor() {
    this.messageQueue = [];
    this.isProcessing = false;
    this.ws = null;
  }
  
  async sendMessage(message) {
    this.messageQueue.push(message);
    await this.processQueue();
  }
  
  async processQueue() {
    if (this.isProcessing || !this.ws || this.ws.readyState !== WebSocket.OPEN) {
      return;
    }
    
    this.isProcessing = true;
    while (this.messageQueue.length > 0) {
      const message = this.messageQueue.shift();
      try {
        await new Promise((resolve, reject) => {
          this.ws.send(JSON.stringify(message));
          // 等待服务器确认
          const handler = (event) => {
            const response = JSON.parse(event.data);
            if (response.id === message.id) {
              this.ws.removeEventListener('message', handler);
              resolve();
            }
          };
          this.ws.addEventListener('message', handler);
          
          // 超时处理
          setTimeout(() => {
            this.ws.removeEventListener('message', handler);
            reject(new Error('Timeout'));
          }, 5000);
        });
      } catch (error) {
        console.error('Send failed:', error);
        this.messageQueue.unshift(message); // 重新放回队列
        break;
      }
    }
    this.isProcessing = false;
  }
}

4. 二进制数据处理

TypeScript 复制代码
// 明确指定数据类型
ws.binaryType = 'arraybuffer'; // 或 'blob'

// 发送二进制数据
const buffer = new ArrayBuffer(32);
const view = new Uint8Array(buffer);
// ... 填充数据
ws.send(buffer);

// 接收二进制数据
ws.onmessage = (event) => {
  if (event.data instanceof ArrayBuffer) {
    const view = new Uint8Array(event.data);
    // 处理二进制数据
  } else {
    // 处理文本数据
    const text = event.data;
  }
};

5. WebSocket状态管理

TypeScript 复制代码
// 状态检查
function sendSafe(ws, data) {
  if (!ws) {
    throw new Error('WebSocket not initialized');
  }
  
  switch (ws.readyState) {
    case WebSocket.CONNECTING:
      // 可以加入队列等待
      return new Promise((resolve) => {
        ws.addEventListener('open', () => {
          ws.send(data);
          resolve();
        }, { once: true });
      });
      
    case WebSocket.OPEN:
      ws.send(data);
      return Promise.resolve();
      
    case WebSocket.CLOSING:
    case WebSocket.CLOSED:
      throw new Error('WebSocket is closing or closed');
      
    default:
      throw new Error('Unknown WebSocket state');
  }
}

6. 安全注意事项

TypeScript 复制代码
// 1. WSS 而非 WS(生产环境)
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.host}/ws`;

// 2. 验证消息来源
ws.onmessage = (event) => {
  try {
    const data = JSON.parse(event.data);
    
    // 验证消息结构
    if (!isValidMessage(data)) {
      console.warn('Invalid message structure');
      return;
    }
    
    // 限制消息大小
    if (event.data.length > MAX_MESSAGE_SIZE) {
      console.warn('Message too large');
      return;
    }
  } catch (error) {
    console.error('Message parse error:', error);
  }
};

// 3. 认证令牌
function initWebSocket(token) {
  const ws = new WebSocket(`${wsUrl}?token=${token}`);
  
  // 定期刷新token
  setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify({
        type: 'refresh_token',
        token: getNewToken()
      }));
    }
  }, TOKEN_REFRESH_INTERVAL);
}
相关推荐
IT猿手6 小时前
实现NAPT、Easy-IP、NATserver、NATstatic
网络
迪康Defender6 小时前
终端供应链安全:应用白名单与软件正版化检测落地|终端安全治理实践
运维·服务器·网络·安全·web安全·自动化·运维开发
Yves..6 小时前
HTTP 协议学习笔记:从报文结构到抓包实践
网络协议·http·fiddler
xiaoye-duck8 小时前
《C++ 项目:手写大模型接入 SDK》DeepSeek接口设计(下):流式响应实现和测试
开发语言·网络·c++·语言模型
其实防守也摸鱼8 小时前
信创安全竞赛知识总结与题库
大数据·网络·人工智能·算法·安全·php
万联WANFLOW9 小时前
异地厂区视频监控远程运维:从组网到安全的实施要点
运维·网络·安全·企业组网·sdwan
衍玊9 小时前
深入剖析 TCP/IP 网络通信原理与内核实现
服务器·网络·tcp/ip
.Bryce.10 小时前
从零到一开发技术名词大全:从需求分析到 AI Agent 工程
java·网络·人工智能·agent·需求分析·agent评测
Black蜡笔小新11 小时前
上云网关/端口穿透/设备上云EasyNTS:无需公网IP、也不改防火墙,设备怎么从内网跑到外网去
网络·网络协议·tcp/ip
Escalating_xu12 小时前
【Linux 网络编程】五种 I/O 模型与非阻塞 I/O:从“等数据”到正确处理 EAGAIN
java·linux·网络