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);
}
相关推荐
Dillon Dong几秒前
Linux后台抓包利器:`nohup`与`tcpdump`的完美结合
linux·网络·tcpdump
爬山算法7 分钟前
Netty(26)如何实现基于Netty的RPC框架?
网络·网络协议·rpc
玥轩_52143 分钟前
OSPF路由协议单区域配置
服务器·网络·智能路由器·交换机·ospf·动态路由
专业开发者1 小时前
照明如何成为建筑网络的平台
网络·物联网
峰顶听歌的鲸鱼1 小时前
15.docker:网络
运维·网络·docker·容器·云计算·php·学习方法
catchadmin1 小时前
使用 PHP 和 WebSocket 构建实时聊天应用 完整指南
开发语言·websocket·php
JIes__1 小时前
网络协议——网络层协议
网络协议
真正的醒悟1 小时前
AI中的动态路由协议
网络·智能路由器
网安INF2 小时前
SSL/TLS体系结构
网络·网络协议·网络安全·ssl
不染尘.2 小时前
TCP客户服务器编程模型
linux·服务器·网络·网络协议·tcp/ip·计算机网络·ssh