一、为什么需要WebSocket?

想象一下这样的场景:你在网页上聊天,每发一条消息都要手动刷新页面才能看到回复——这简直像回到了2005年。传统的HTTP协议就像写信,发一次请求等一次回复,而WebSocket则是打电话,建立连接后双方随时可以交流。

核心优势

  • 双向通信:服务器可以主动推数据给前端(比如股票行情实时更新)
  • 低延迟:省去了反复建立连接的耗时(HTTP的3次握手再见啦)
  • 轻量级:数据头只有2-10字节,比HTTP headers小得多
// 技术栈:JavaScript + WebSocket API
// 示例1:建立基础连接
const socket = new WebSocket('wss://your-websocket-server.com');

// 监听连接成功事件
socket.addEventListener('open', (event) => {
  console.log('连接已建立,可以开始聊天了!');
  socket.send('你好服务器,我是客户端A'); // 发送第一条消息
});

// 监听服务器消息
socket.addEventListener('message', (event) => {
  console.log('收到服务器消息:', event.data);
});

二、如何正确建立和维持连接?

WebSocket用起来简单,但要稳定运行得像老黄牛,得注意这些细节:

1. 连接保活
网络不稳定时自动重连是基本操作:

// 示例2:自动重连机制
let socket;
const maxRetry = 5; // 最大重试次数

function connect() {
  socket = new WebSocket('wss://your-server.com');

  socket.onclose = () => {
    console.log('连接断开,3秒后重试...');
    if (maxRetry-- > 0) setTimeout(connect, 3000);
  };
}

connect(); // 初始连接

2. 心跳检测
防止连接假死,定期发个"心跳包":

// 示例3:心跳检测
setInterval(() => {
  if (socket.readyState === WebSocket.OPEN) {
    socket.send(JSON.stringify({ type: 'heartbeat' }));
  }
}, 30000); // 每30秒一次

三、数据格式的优雅处理

直接发字符串太原始,推荐两种结构化方案:

方案A:JSON包装
适合大多数业务场景

// 示例4:结构化消息协议
function sendMessage(type, payload) {
  socket.send(JSON.stringify({
    type,       // 消息类型:chat/notification/alert
    timestamp: Date.now(),
    data: payload
  }));
}

// 使用示例
sendMessage('chat', { text: '今晚吃啥?', userId: 123 });

方案B:二进制数据
适合传输文件或音视频流

// 示例5:发送二进制数据
const fileInput = document.getElementById('file-upload');
fileInput.addEventListener('change', (e) => {
  const file = e.target.files[0];
  const reader = new FileReader();
  
  reader.onload = (event) => {
    socket.send(event.target.result); // 直接发送ArrayBuffer
  };
  reader.readAsArrayBuffer(file);
});

四、必须知道的性能优化技巧

1. 消息合并
高频场景下(如实时股价),别一条条发:

// 示例6:批量消息处理
let messageQueue = [];
const BATCH_INTERVAL = 100; // 每100ms批量发送一次

setInterval(() => {
  if (messageQueue.length > 0) {
    socket.send(JSON.stringify(messageQueue));
    messageQueue = [];
  }
}, BATCH_INTERVAL);

// 业务代码调用
function pushToQueue(msg) {
  messageQueue.push(msg);
}

2. 连接共享
多个功能复用同个连接:

// 示例7:多频道复用连接
function subscribe(channel) {
  socket.send(JSON.stringify({
    action: 'subscribe',
    channel: channel  // 如:news/weather/stocks
  }));
}

// 同时接收新闻和天气
subscribe('news');
subscribe('weather');

五、典型业务场景实战

场景1:在线协作编辑
多人同时编辑文档时,用WebSocket同步内容:

// 示例8:协同编辑实现
document.getElementById('editor').addEventListener('input', (e) => {
  const changes = {
    position: e.target.selectionStart,
    text: e.target.value
  };
  socket.send(JSON.stringify({
    type: 'document_edit',
    changes
  }));
});

场景2:实时游戏状态同步
玩家移动位置时立即广播给其他玩家:

// 示例9:游戏状态同步
player.onMove((x, y) => {
  socket.send(JSON.stringify({
    type: 'player_move',
    x,
    y,
    playerId: 'player_123'
  }));
});

六、避坑指南

1. 注意连接状态
发送前务必检查:

// 示例10:安全发送消息
function safeSend(data) {
  if (socket.readyState !== WebSocket.OPEN) {
    console.error('连接未就绪');
    return false;
  }
  socket.send(data);
  return true;
}

2. 控制消息体积
大消息分片发送:

// 示例11:大文件分片传输
const CHUNK_SIZE = 1024 * 16; // 16KB每片

function sendLargeFile(file) {
  const chunkCount = Math.ceil(file.size / CHUNK_SIZE);
  
  for (let i = 0; i < chunkCount; i++) {
    const chunk = file.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE);
    socket.send(chunk);
  }
}

七、技术选型对比

方案 优点 缺点
原生WebSocket 浏览器内置,零依赖 缺乏高级功能如自动重连
Socket.IO 断线重连/多路复用 体积较大(100KB+)
WS Node.js后端首选 需要自行处理跨域

八、安全防护要点

  1. 必须使用wss协议(WebSocket over TLS)
  2. 验证消息来源
// 示例12:消息来源验证
socket.addEventListener('message', (event) => {
  try {
    const msg = JSON.parse(event.data);
    if (msg.token !== '预共享密钥') {
      throw new Error('非法消息');
    }
    // 处理合法消息...
  } catch (e) {
    console.error('消息验证失败', e);
  }
});

九、未来演进方向

  1. HTTP/3支持:基于QUIC协议提升弱网表现
  2. WebTransport:下一代多路传输协议(Chrome已实验性支持)
// 示例13:未来可能这样写
const transport = new WebTransport('https://example.com');
const stream = await transport.createBidirectionalStream();

十、总结与决策建议

适合WebSocket的场景

  • 需要服务器主动推送(聊天室、实时监控)
  • 高频双向交互(在线游戏、协同编辑)

不建议使用的场景

  • 简单数据查询(用HTTP够用)
  • 超低频通知(用轮询或SSE更简单)

记住:技术没有银弹,选对工具比会用工具更重要!