简介
WebSocket 是一种能够通过单一 TCP 连接在客户端和服务器之间实现全双工、持久通信的协议。与无状态且单向的 HTTP 不同,WebSocket 提供了低延迟的实时交互——这使其成为聊天应用、实时信息流、协同编辑和物联网 (IoT) 场景的理想选择。
在现代架构中,API 网关通常作为所有客户端流量的入口。通过 API 网关支持 WebSocket 流量需要特殊的处理机制,因为它偏离了 HTTP 的请求-响应模型。在本文中,我们将探讨 API 网关如何支持 WebSocket 连接、相关的架构考量以及实现的最佳实践。
什么是 WebSocket,它有何不同?
WebSocket 与 HTTP 对比
| 特性 | HTTP | WebSocket |
|---|---|---|
| 连接 | 短暂的,每次请求独立 | 持久的,全双工 |
| 协议 | 请求-响应模型 | 双向消息传递 |
| 开销 | 较高(每个请求都带有请求头) | 低(仅需一次握手) |
| 适用场景 | REST API、静态内容 | 实时应用、数据流 |
WebSocket 握手
WebSocket 连接始于一个 HTTP Upgrade(升级)请求:
1GET /chat HTTP/1.1
2Host: server.example.com
3Upgrade: websocket
4Connection: Upgrade
5Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
6Sec-WebSocket-Version: 13如果服务器支持 WebSocket,它会返回:
1HTTP/1.1 101 Switching Protocols
2Upgrade: websocket
3Connection: Upgrade
4Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=在此次握手完成后,连接即被升级,客户端和服务器都可以独立地发送消息了。
通过 API 网关路由 WebSocket 的挑战
- 连接持久性:WebSocket 连接可能持续数小时。网关必须高效地管理这些长连接。
- 负载均衡:与无状态的 HTTP 请求不同,WebSocket 会话必须保持粘性或一致的转发规则。
- 协议升级支持:网关必须理解并支持 HTTP 的 Upgrade(升级)机制。
- 监控与日志记录:实时流量比离散的 HTTP 请求更难进行审查和分析。
- 安全性与限流:需要在不中断实时数据流的情况下执行安全策略。
架构:通过 API 网关的 WebSocket
🔁 流程图:API 网关中的 WebSocket 生命周期
1sequenceDiagram
2 participant Client
3 participant Gateway
4 participant Backend
5 Client->>Gateway: HTTP 升级请求
6 Gateway->>Backend: 代理升级请求
7 Backend-->>Gateway: 101 切换协议
8 Gateway-->>Client: 101 切换协议
9 Note over Client,Backend: WebSocket 隧道建立完成
10 Client-->>Backend: WebSocket 数据帧 (消息)
11 Backend-->>Client: WebSocket 数据帧 (回复)网关职责
- 接收并验证
Upgrade请求 - 维护 TCP 连接状态
- 在客户端和后端之间转发数据帧
- 应用可观测性和安全策略
不同 API 网关如何支持 WebSocket
Apache APISIX
- 通过
websocket路由选项提供原生的 WebSocket 代理功能 - 支持基于 URI、请求头和查询参数进行路由
- 提供支持速率限制和身份认证的插件
配置示例:
1{
2 "uri": "/ws",
3 "upstream": {
4 "type": "roundrobin",
5 "nodes": {
6 "192.168.1.10:8080": 1
7 }
8 },
9 "websocket": true
10}Kong
- 默认开启 WebSocket 支持
- 可结合 TCP stream 插件进行 L4(四层)代理
Envoy
- 在 HTTP 连接管理器中通过
use_websocket: true支持 WebSocket - 全面支持基于请求头的路由
NGINX
- 需要为 Upgrade 请求头进行专门配置
- 没有原生的 WebSocket 感知能力——仅作为 TCP 隧道运行
配置示例:
1location /ws/ {
2 proxy_pass http://backend;
3 proxy_http_version 1.1;
4 proxy_set_header Upgrade $http_upgrade;
5 proxy_set_header Connection "Upgrade";
6}API 网关中的 WebSocket 最佳实践
1. 开启连接的 Keep-Alive 和超时设置
- 确保空闲连接在可配置的时间后被断开。
- 监控并清理僵尸连接。
2. 必要时使用粘性会话 (Sticky Sessions)
- 如果后端是有状态的,请配置会话粘性。
- 使用请求头或 Cookie 来强制执行亲和性路由 (routing affinity)。
3. 实现每连接维度的速率限制
- 通过统计每个客户端的消息数量或带宽来防止滥用。
4. 在初始的 HTTP 升级阶段进行身份认证
- JWT 或 API 密钥验证应在握手完成前进行。
5. 监控连接与指标
- 统计活跃的 WebSocket 会话数
- 记录握手失败和异常终止的情况
📊 监控流程
1sequenceDiagram
2 participant Client
3 participant Gateway
4 participant Metrics
5 Client->>Gateway: WebSocket 请求
6 Gateway-->>Metrics: 记录升级尝试
7 Gateway-->>Client: 101 切换协议
8 Client-->>Gateway: WebSocket 数据帧
9 Gateway-->>Metrics: 记录消息计数/错误总结
WebSocket 开启了实时应用的新篇章。API 网关可以支持 WebSocket 流量,但需要谨慎配置,以处理长连接、保持高性能并确保安全性。
选择一个从一开始就支持原生 WebSocket 路由,并且集成了指标监控和访问策略的 API 网关是明智之举。
常见问题 (FAQ)
1. WebSocket 可以通过网关用 TLS 加密吗?
答:可以。在客户端使用 wss://,并在网关或专用的 TLS 代理处终止 TLS。
2. WebSocket 能在像 Istio 这样的服务网格 (Service Mesh) 中使用吗?
答:可以,但请确保网格代理(如 Envoy)支持连接升级和 TCP 隧道。
3. 我该如何测试 WebSocket 端点?
答:可以使用如 wscat、浏览器开发者工具或支持 WebSocket 的 Postman 等工具。
4. WebSocket 可以实现负载均衡吗?
答:可以,但对于有状态的后端,请使用粘性会话或一致性哈希。
5. 我可以审查或拦截特定的 WebSocket 消息吗?
答:大多数网关会盲目地(不加区分地)代理消息。深度的数据包审查需要额外的中间件或支持 L7(七层)协议分析的代理。
