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);
}
相关推荐
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.14 分钟前
双主模式实现HTTP与MySQL高可用
网络协议·mysql·http
G311354227341 分钟前
本地部署和云端部署的优缺点
网络
噔噔君1 小时前
蜂窝网络模组的MQTT功能
网络
WuLaHH1 小时前
可靠UDP协议RUDP
单片机·网络协议·udp
HaiLang_IT1 小时前
【信息安全毕业设计】基于双层滤波与分割点改进孤立森林的网络入侵检测算法研究
网络·算法·课程设计
k_cik_ci1 小时前
什么是负载均衡?
服务器·网络·负载均衡
I love this bad girl1 小时前
华为无线VRRP热备份
网络
zbtlink1 小时前
为什么建议用poe路由器,但不建议用poe供电?
网络·智能路由器
Hill_HUIL1 小时前
学习日志19-不同VLAN间通信(3)-三层交换机
网络·学习
阿钱真强道1 小时前
10 jetlinks-mqtt-直连设备-属性-读取-返回
linux·服务器·网络·鸿蒙