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);
}
相关推荐
虎头金猫3 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
只睡四小时3 天前
Canvas 弹道联机实战:700 行 + 固定时间步长
python·websocket·html5·游戏开发·canvas
wuyk5553 天前
《WiFi 嵌入式物联网开发全套实战》| 第 16 章 ESP32 AP+STA 双模共存原理与工程坑点
网络·stm32·物联网
XUEYUAN52123 天前
ASN 自治系统号风控:平台如何通过 IP 所属自治域批量识别代理流量
python·网络协议·http·网络安全·socks5
QYRdata3 天前
年均增速24.2%!机器人数据湖未来六年增长动能强劲
网络·机器人·服务发现
CHENKONG_CK3 天前
破解制鞋打磨痛点:RFID赋能去毛刺工序自动化升级
网络·单片机·嵌入式硬件·网络协议·tcp/ip
chshang19923 天前
工业路由器是什么?浅谈5G工业网络中的IR602
网络·物联网·5g·智能路由器
萧瑟余晖3 天前
Netty 核心组件与 Reactor 模型详解
网络·架构
ITxiaobing20233 天前
IP 定位服务选型指南:从准确率到工程落地的技术考察
linux·服务器·网络
wuyk5553 天前
【Socket 进阶之路】第 9 章 Linux 网络服务量产稳定性优化|心跳保活、TIME_WAIT、SO_LINGER、内存池、断线重连、完整异常防护框架
linux·服务器·开发语言·网络·物联网