# WebSocket

WebSocket 是一种基于 TCP 的全双工通信协议,它的核心作用是打破 HTTP 协议 “请求 - 响应” 的单向通信限制,让客户端和服务端建立连接后,能双向、实时地收发数据

它的工作流程分两步:

  1. 握手阶段:依赖 HTTP 完成。客户端发送一个带 Upgrade: websocket 字段的 HTTP 请求,服务端返回 101 状态码,协议就从 HTTP 升级为 WebSocket,建立持久连接。
  2. 通信阶段:连接建立后,双方不需要每次请求都带冗余的 HTTP 头,直接以 “帧” 的形式传输数据,延迟极低。

对比 HTTP 的话,HTTP 是 “客户端问、服务端答”,服务端不能主动发消息;而 WebSocket 是 “电话接通后,双方随时能说话”,特别适合实时聊天、股票行情、在线游戏这类场景。

# 补充:WebSocket 核心优势(面试加分点)

  1. 全双工:同一连接上,客户端和服务端可同时发数据,不像 HTTP 同一时刻只能单向传输。
  2. 长连接低开销:一次握手,持久连接,避免 HTTP 短连接频繁创建 / 销毁 TCP 连接的性能损耗。
  3. 轻量级:数据帧头很小,比 HTTP 请求头节省带宽。

# 二、 如何解释 WebSocket 重连机制(实战重点,面试官超关心)

面试官大概率会追问 “WebSocket 连接断了怎么办?”,这时候要讲重连的必要性 + 核心思路 + 具体实现方案,结合代码思路更佳:

WebSocket 连接很容易因为网络波动、服务端重启、客户端休眠(比如浏览器切后台)而断开,所以必须实现自动重连机制,保证通信的可靠性。

重连的核心思路是:监听连接关闭 / 错误事件 → 延迟重试 → 避免频繁重试 → 重连成功后恢复业务逻辑

# 1. 重连机制的核心实现步骤(分 4 步,带伪代码思路)

# (1)监听断开事件,触发重连

WebSocket 有 oncloseonerror 两个事件,只要触发,就说明连接断了,需要启动重连。

javascript

运行

let ws = null;
// 初始化连接方法
function initWebSocket() {
  ws = new WebSocket('wss://xxx.com/chat');
  
  // 连接成功
  ws.onopen = () => {
    console.log('连接成功');
    // 重连成功后,可发送心跳或恢复订阅
    sendHeartbeat();
  };
  
  // 接收消息
  ws.onmessage = (e) => {
    console.log('收到消息', e.data);
  };
  
  // 连接关闭/错误,触发重连
  ws.onclose = (e) => {
    console.log('连接关闭,准备重连');
    reconnect();
  };
  ws.onerror = (e) => {
    console.log('连接错误,准备重连');
    reconnect();
  };
}

# (2)延迟重试 + 指数退避(避免频繁请求压垮服务端)

核心原则:不能连接一断就立刻重试(比如网络彻底断了,重试也是白耗资源),要加延迟,并且失败次数越多,延迟越长(指数退避策略),同时设置最大重试次数,防止无限重试。

javascript

运行

let retryCount = 0; // 重试次数
const MAX_RETRY = 10; // 最大重试次数
const BASE_DELAY = 1000; // 基础延迟时间(1秒)

function reconnect() {
  // 超过最大重试次数,停止重连,提示用户
  if (retryCount >= MAX_RETRY) {
    alert('网络异常,无法重连,请刷新页面');
    return;
  }
  
  // 指数退避:延迟时间 = 基础延迟 * 2^重试次数
  const delay = BASE_DELAY * Math.pow(2, retryCount);
  retryCount++;
  
  // 延迟后重新初始化连接
  setTimeout(() => {
    console.log(`第${retryCount}次重连,延迟${delay}ms`);
    initWebSocket();
  }, delay);
}

# (3)心跳机制(预防 “假死” 连接)

很多时候,连接物理没断,但已经失效(比如防火墙超时断开),这种情况 onclose 不会触发,需要用心跳包检测连接状态。

心跳机制:客户端定期给服务端发一个 “心跳消息”,服务端收到后回复 “心跳响应”。如果客户端多次发心跳都没收到响应,就主动断开并触发重连。

javascript

运行

let heartbeatTimer = null;
// 发送心跳
function sendHeartbeat() {
  // 定时发送心跳(比如每10秒发一次)
  heartbeatTimer = setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send('ping'); // 心跳消息,格式自定义
    } else {
      // 连接状态不对,清除定时器
      clearInterval(heartbeatTimer);
    }
  }, 10000);
}

// 服务端返回pong,说明连接正常
ws.onmessage = (e) => {
  if (e.data === 'pong') {
    console.log('心跳正常');
    // 收到响应,重置重试次数(如果之前有失败)
    retryCount = 0;
  } else {
    // 处理业务消息
  }
};

# (4)重连成功后恢复业务

重连成功后,需要恢复之前的业务状态,比如:

  • 重新发送之前未成功发送的消息;
  • 重新订阅用户关注的频道(比如聊天房间);
  • 清空重试次数,重置心跳定时器。

# 三、 面试总结话术(一句话收尾)

总的来说,WebSocket 解决了 HTTP 实时通信的痛点,而重连机制是保证 WebSocket 稳定性的关键,核心是监听断开事件 + 指数退避重试 + 心跳检测 + 业务恢复,这样就能在复杂的网络环境下,保证实时通信的可靠性。

本章目录