WebSockets
本部分参考文档涵盖了对 Servlet 栈的支持,包括原始 WebSocket 交互、通过 SockJS 实现的 WebSocket 模拟,以及通过 STOMP 作为 WebSocket 之上的子协议实现的发布-订阅消息。
WebSocket 简介
WebSocket 协议 (RFC 6455) 提供了一种标准化的方式,通过单个 TCP 连接在客户端和服务器之间建立全双工、双向通信通道。它是与 HTTP 不同的 TCP 协议,但设计为在 HTTP 之上工作,使用 80 和 443 端口,并允许重用现有的防火墙规则。
WebSocket 交互始于一个 HTTP 请求,该请求使用 HTTP Upgrade 标头来升级(在本例中为切换)到 WebSocket 协议。以下示例显示了这种交互:
GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket (1)
Connection: Upgrade (2)
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080Upgrade标头。- 使用
Upgrade连接。
具有 WebSocket 支持的服务器将返回类似以下内容的输出,而不是通常的 200 状态码:
HTTP/1.1 101 Switching Protocols (1)
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp- 协议切换。
握手成功后,HTTP 升级请求底层的 TCP 套接字保持打开状态,客户端和服务器可以继续发送和接收消息。
HTTP 与 WebSocket
尽管 WebSocket 被设计为与 HTTP 兼容并以 HTTP 请求开始,但重要的是要理解这两种协议会导致截然不同的架构和应用程序编程模型。
在 HTTP 和 REST 中,应用程序被建模为许多 URL。为了与应用程序交互,客户端以请求-响应方式访问这些 URL。服务器根据 HTTP URL、方法和标头将请求路由到适当的处理程序。
相比之下,在 WebSocket 中,通常只有一个用于初始连接的 URL。随后,所有应用程序消息都在同一个 TCP 连接上流动。这指向了一种完全不同的异步、事件驱动的消息传递架构。
何时使用 WebSocket
WebSocket 可以使网页更加动态和交互。然而,在许多情况下,AJAX 和 HTTP 流或长轮询的组合可以提供简单有效的解决方案。
例如,新闻、邮件和社交源需要动态更新,但每隔几分钟更新一次可能完全没问题。另一方面,协作、游戏和金融应用需要更接近实时。
仅延迟并不是决定因素。如果消息量相对较低(例如,监控网络故障),HTTP 流或轮询可以提供有效的解决方案。正是低延迟、高频度和高容量的结合,才使得使用 WebSocket 成为最佳方案。
补充教学
1. 全双工通信的意义
传统的 HTTP 是“半双工”的:客户端请求,服务器响应。服务器无法主动推送数据。WebSocket 改变了这一点,使得服务器可以在有新数据时立即推送到客户端,非常适合股票行情、实时聊天室等场景。
2. 握手过程
WebSocket 复用了 HTTP 的握手过程。这意味着它可以轻松通过代理服务器和防火墙。一旦握手成功,它就不再受 HTTP 协议限制,而是通过二进制帧(Frames)进行高效通信。
3. Nginx 配置
如果你在 Spring 应用前使用了 Nginx 等反向代理,必须显式配置以支持 Upgrade 标头:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";否则,握手将无法通过代理。