WebScoket

发布于 2026-06-12 21:50 2872 字 15 min read

在 Web 应用早期,浏览器和服务器之间的通信几乎完全依赖 HTTP 请求。用户点击按钮,浏览器发起请求,服务器返回响应。这种模式简单、可靠,也非常适合传统页面加载和表单提交。 但随着聊天系统、在线协作、实时行情、多人游戏、消息通知等场景出现,传统 HTTP 的“一问一答”模式开始显得笨重。客户端想要知道服务器有没有新...

在 Web 应用早期,浏览器和服务器之间的通信几乎完全依赖 HTTP 请求。用户点击按钮,浏览器发起请求,服务器返回响应。这种模式简单、可靠,也非常适合传统页面加载和表单提交。

但随着聊天系统、在线协作、实时行情、多人游戏、消息通知等场景出现,传统 HTTP 的“一问一答”模式开始显得笨重。客户端想要知道服务器有没有新消息,就必须不断轮询服务器。轮询不仅浪费带宽,也增加服务器压力,实时性还不够理想。

WebSocket 正是在这种背景下出现的。它让浏览器和服务器之间建立一条持久的双向通信通道,使双方都可以随时主动发送消息。

一、WebSocket 是什么?

WebSocket 是一种基于 TCP 的全双工通信协议。它允许客户端和服务器在一次连接建立后,持续保持通信通道,并且双方都能主动向对方发送数据。

简单来说,HTTP 更像是:

客户端:你有新消息吗?
服务器:没有。

客户端:你有新消息吗?
服务器:没有。

客户端:你有新消息吗?
服务器:有,给你。

WebSocket 更像是:

客户端:我们建立一个长期连接吧。
服务器:可以。

服务器:有新消息了,直接发给你。
客户端:收到。

这种模式非常适合实时性要求较高的业务。

二、WebSocket 和 HTTP 的关系

WebSocket 并不是 HTTP 的替代品,而是对 HTTP 通信能力的一种补充。

WebSocket 的连接通常从一个 HTTP 请求开始。客户端会发送一个带有 Upgrade 头的 HTTP 请求,告诉服务器:“我想把这个连接升级成 WebSocket。”

示意请求如下:

GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xxx
Sec-WebSocket-Version: 13

如果服务器支持 WebSocket,就会返回类似响应:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: xxx

状态码 101 Switching Protocols 表示协议切换成功。之后,这条连接就不再按照普通 HTTP 请求响应模式通信,而是进入 WebSocket 双向通信阶段。

三、为什么不用 HTTP 轮询?

在 WebSocket 普及之前,实时通信常见方案主要有三种:

  1. 短轮询
    1. 短轮询最简单,客户端每隔几秒请求一次服务器。但如果大多数请求都没有新数据,就会造成大量无效请求。
  2. 长轮询
    1. 长轮询比短轮询稍好。客户端发送请求后,服务器如果没有新数据,会暂时挂起请求,直到有数据或超时再返回。它减少了一些无效请求,但本质上仍然是 HTTP 请求响应模型。
  3. Server-Sent Events
    1. Server-Sent Events,简称 SSE,允许服务器持续向客户端推送事件。但它主要是单向通信:服务器推给客户端。如果客户端也要频繁发送消息,仍然需要 HTTP 请求配合。

WebSocket 的优势在于,它是真正的双向通信。客户端和服务器都可以主动发送数据,通信开销更低,实时性更好。

四、WebSocket 的核心特点

1. 全双工通信

WebSocket 最大的特点是全双工。连接建立后,客户端和服务器可以同时发送和接收消息,不需要等待对方先发起请求。这对聊天、直播弹幕、在线游戏、协作文档等场景非常重要。

2. 持久连接

WebSocket 建立后会保持连接,除非客户端、服务器或网络主动断开。相比 HTTP 每次请求都要携带大量头部信息,WebSocket 后续数据帧更轻量。

3. 低延迟

由于连接已经建立,后续通信不需要重复握手。服务器有数据时可以立刻推送给客户端,因此延迟通常比轮询方案更低。

4. 支持文本和二进制数据

WebSocket 可以传输文本,也可以传输二进制数据,比如图片片段、音视频数据、协议缓冲区数据等。

五、WebSocket 适合哪些场景?

WebSocket 不是所有业务都需要,但在以下场景中非常有价值:

  • 即时聊天
  • 在线客服
  • 实时通知
  • 协作文档
  • 实时看板
  • 股票、币价、体育比分等实时行情
  • 多人在线游戏
  • 直播间弹幕
  • 在线代码协作或远程终端

判断是否需要 WebSocket,可以问一个简单问题:“服务器是否需要在客户端没有请求时,主动把数据推给客户端?”,如果答案是肯定的,WebSocket 很可能是合适方案。

六、浏览器中如何使用 WebSocket?

由于浏览器原生支持 WebSocket API,使用非常简单。

const socket = new WebSocket("wss://example.com/socket");

socket.addEventListener("open", () => {
  console.log("WebSocket connected");
  socket.send(JSON.stringify({ type: "hello" }));
});

socket.addEventListener("message", (event) => {
  const data = JSON.parse(event.data);
  console.log("Received:", data);
});

socket.addEventListener("close", () => {
  console.log("WebSocket closed");
});

socket.addEventListener("error", (error) => {
  console.error("WebSocket error:", error);
});

其中:

  • ws:// 类似 HTTP
  • wss:// 类似 HTTPS,表示加密 WebSocket 连接

生产环境中应优先使用 wss://,避免通信被窃听或篡改。

七、服务端简单示例

以 Node.js 的 ws 库为例:

import { WebSocketServer } from "ws";

const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", (socket) => {
  console.log("client connected");

  socket.on("message", (message) => {
    console.log("received:", message.toString());

    socket.send(JSON.stringify({
      type: "echo",
      payload: message.toString()
    }));
  });

  socket.on("close", () => {
    console.log("client disconnected");
  });
});

这个例子中,服务器接收客户端消息后,会原样返回一条 echo 消息。

真实业务中,服务端通常还需要处理身份认证、房间管理、消息广播、心跳检测、限流、断线重连等问题。

八、WebSocket 的常见问题

1. 身份认证

WebSocket 连接建立后不像普通 HTTP 请求那样每次都携带完整请求上下文,因此认证需要提前设计。

常见方式有:

  • 在连接 URL 中携带短期 token
  • 在 WebSocket 子协议中传递认证信息
  • 连接建立后发送认证消息
  • 借助 Cookie 和服务端 Session

例如:

const socket = new WebSocket("wss://example.com/socket?token=xxx");

不过 URL 中的 token 可能出现在日志里,因此更推荐使用短期、可撤销、权限有限的 token。

2. 心跳检测

网络连接可能因为代理、NAT、防火墙或移动网络切换而悄悄断开。客户端和服务器不能只依赖 close 事件判断连接是否还活着,因此通常需要心跳机制。一种常见方式是:

客户端定时发送 ping
服务器收到后返回 pong
如果连续多次没有 pong,客户端主动重连

服务端也可以主动发送 ping,用于清理已经失效的连接。

3. 断线重连

WebSocket 是长连接,但长连接并不意味着永远连接。网络抖动、服务重启、页面休眠、移动端切网都可能导致断开。客户端应该实现重连机制,并且最好使用指数退避,避免大量客户端同时重连压垮服务器。

// 示意逻辑:

let retryCount = 0;

function connect() {
  const socket = new WebSocket("wss://example.com/socket");

  socket.onopen = () => {
    retryCount = 0;
  };

  socket.onclose = () => {
    const delay = Math.min(1000 * 2 ** retryCount, 30000);
    retryCount += 1;
    setTimeout(connect, delay);
  };
}

connect();

4. 消息可靠性

WebSocket 只负责传输,不天然保证业务层消息一定被正确处理。如果业务对可靠性要求高,比如订单状态、交易通知、协作文档操作,就需要设计:

  • 消息 ID
  • ACK 确认机制
  • 消息重试
  • 去重处理
  • 服务端消息持久化
  • 客户端断线后补拉未读消息

例如,客户端发送消息:

{
  "id": "msg_123",
  "type": "chat.message",
  "payload": {
    "text": "hello"
  }
}

服务器处理后返回:

{
  "type": "ack",
  "id": "msg_123"
}

这样客户端才能知道这条消息是否真正被服务端接收。

5. 水平扩展

单机 WebSocket 很容易理解,但真实生产环境往往是多台服务器。问题在于:用户 A 连接在服务器 1,用户 B 连接在服务器 2。如果 A 给 B 发消息,服务器 1 需要某种方式把消息转给服务器 2。

常见解决方案包括:

  • 使用 Redis Pub/Sub
  • 使用 Kafka、RabbitMQ、NATS 等消息系统
  • 使用统一网关管理连接
  • 使用粘性会话让同一用户尽量连接到固定实例

架构可以简化理解为:

Client A -> WebSocket Server 1
Client B -> WebSocket Server 2

Server 1 -> Message Broker -> Server 2

消息系统在这里承担跨实例广播和解耦的作用。

九、WebSocket 和 SSE 怎么选?

  • 如果业务只是服务器向客户端单向推送,比如通知流、日志流、状态更新,SSE 可能更简单。
  • 如果业务需要客户端和服务器频繁双向通信,比如聊天、游戏、协作编辑,WebSocket 更合适。

简单对比:

特性WebSocketSSE
通信方向双向服务器到客户端
协议独立协议,HTTP Upgrade 后切换基于 HTTP
浏览器支持广泛支持广泛支持
二进制支持支持不直接支持
自动重连需要自己实现浏览器原生支持
适合场景聊天、游戏、协作通知、日志、行情推送

十、生产环境最佳实践

使用 WebSocket 时,建议遵循这些原则:

  • 生产环境使用 wss://
  • 设计清晰的消息协议
  • 每条重要消息带唯一 ID
  • 做好认证和权限校验
  • 实现心跳检测
  • 实现断线重连
  • 服务端清理失效连接
  • 对连接数和消息频率限流
  • 避免把 WebSocket 当成数据库同步工具滥用
  • 对关键消息做持久化和补偿
  • 多实例部署时引入消息中间件
  • 监控连接数、消息延迟、断线率和错误率

一个成熟的 WebSocket 系统,难点通常不在“建立连接”,而在连接之后的治理。

十一、一个推荐的消息格式

为了让 WebSocket 通信更可维护,建议定义统一消息结构:

{
  "id": "msg_001",
  "type": "chat.message",
  "timestamp": 1710000000000,
  "payload": {
    "roomId": "room_1",
    "content": "Hello WebSocket"
  }
}

其中:

  • id 用于追踪和去重
  • type 用于区分消息类型
  • timestamp 用于排序和调试
  • payload 存放业务数据

错误消息也应标准化:

{
  "type": "error",
  "code": "UNAUTHORIZED",
  "message": "Authentication failed"
}

这样前后端就能围绕协议协作,而不是在大量零散字段中互相猜测。

十二、总结

WebSocket 解决的是 Web 应用中的实时双向通信问题。它通过一次握手建立持久连接,让客户端和服务器可以低延迟、低开销地互相发送消息。

它非常适合聊天、协作、游戏、实时看板和行情推送等场景。但 WebSocket 不是简单地“连上就完事”。真正的工程重点在于认证、心跳、重连、消息可靠性、水平扩展和监控治理。

如果只是单向推送,SSE 可能更轻量;如果需要频繁双向通信,WebSocket 通常是更好的选择。

WebSocket 让 Web 从“客户端主动询问”走向了“服务端实时对话”,但要把它用好,需要的不只是协议能力,更是完整的实时系统设计。

喜欢的话,留下你的评论吧~