跳到主要内容

1. 引言

WebSocket 协议使客户端和服务器能够在单个 TCP 连接上进行全双工通信. 该协议由 opening handshake (开启握手) 和基本的消息 framing (成帧) 组成, 并运行在 TCP 之上.

本规范的目标是为需要与服务器进行双向通信的基于浏览器的应用提供一种机制, 这种机制不依赖打开多个 HTTP 连接 (例如使用 XMLHttpRequest 或 <iframe> 和长轮询).

1.1 背景

历史上, 创建需要客户端与服务器之间双向通信的 Web 应用 (例如即时消息和游戏应用) 时, 往往需要滥用 HTTP: 一边轮询服务器以获取更新, 一边把上行通知作为独立的 HTTP 调用发送.

这会带来多种问题:

  • 对每个客户端, 服务器被迫使用多个不同的底层 TCP 连接: 一个用于向客户端发送信息, 每个传入消息又需要一个新的连接
  • 线缆协议开销很高, 因为每个客户端到服务器的消息都带有 HTTP header
  • 客户端脚本被迫维护从出站连接到入站连接的映射, 以跟踪回复

更简单的方案是在两个方向的流量中使用单个 TCP 连接. 这正是 WebSocket 协议所提供的能力. 与 WebSocket API 结合后, 它为网页到远程服务器的双向通信提供了 HTTP 轮询之外的替代方案.

1.2 协议概览

该协议包含两个部分: 握手和数据传输.

客户端发起的 handshake (握手) 如下所示:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

服务器返回的握手如下所示:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

握手的要点:

  • 客户端请求是有效的 HTTP Upgrade 请求
  • 添加了多个 WebSocket 专用 header
  • 服务器以状态码 101 响应

连接建立后, 客户端和服务器可以在任意时间沿两个方向来回发送数据.

1.3 设计理念

WebSocket 协议基于以下原则设计:

  1. 基于 frame (帧) 而非基于 stream (流) 的协议: 基于帧的协议允许为每个帧关联元数据, 并允许协议向应用层保留消息边界
  2. Origin 模型: 使用浏览器 origin 模型来保障安全
  3. 单个 TCP 连接: 以便在 HTTP 端口 80 和 443 上工作
  4. 独立于 HTTP: 虽然握手会被 HTTP 服务器解释为 Upgrade 请求, 但协议本身是独立的
  5. 可扩展性: 通过扩展和子协议机制支持未来扩展

1.4 安全模型

WebSocket 协议使用 Web 浏览器常用的 origin 模型. 协议包含一个 Origin header 字段, 服务器可以使用它来决定是否接受来自给定 origin 的 WebSocket 连接.

此外:

  • 推荐使用 TLS 加密连接 (wss://)
  • 从客户端到服务器的 frame 必须被 mask
  • 协议包含 frame 类型, opcode 等机制, 用于防止缓存投毒

参考链接