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);
}
相关推荐
WHFENGHE1 小时前
输电线路微气象在线监测装置——电力安全的实时守护者
网络·安全
I_ltt_Itw,1 小时前
Python协程学习笔记
开发语言·网络·python
网安小白的进阶之路1 小时前
B模块 安全通信网络 第一门课 园区网实现与安全-3-项目实战
网络·安全
ICT技术最前线1 小时前
内网穿透目前最好的解决方案是什么?
网络·内网穿透
EleganceJiaBao1 小时前
【ESP8266】使用 ESP8266 + CoolTerm + Packet Sender 构建 TCP 通信的完整调试流程
网络协议·tcp/ip·wi-fi·esp8266·coolterm·packet sender
老蒋新思维1 小时前
创客匠人 2025 峰会启示:AI 重构企业管理领域知识变现的效率逻辑
人工智能·网络协议·tcp/ip·重构·知识付费·创始人ip·创客匠人
羑悻的小杀马特2 小时前
openGauss 驱动的知识数据湖建设实践
网络·opengauss
6***83052 小时前
VMware虚拟机配置桥接网络
开发语言·网络·php
g***55752 小时前
详解 为什么 tcp 会出现 粘包 拆包 问题
网络·tcp/ip·php