WebSocket 协议(RFC 6455)提供了一种标准化的方式,在客户和服务器之间通过单一的 TCP 连接建立全双工、双向的通信通道。它是一个不同于 HTTP 的 TCP 协议,但被设计为在 HTTP 上工作,使用 80 和 443 端口,并允许重新使用现有的防火墙规则。
WebSocket 互动始于一个 HTTP 请求,该请求使用 HTTP 升级标头来升级,或者在本例中,切换到 WebSocket 协议。下面的例子显示了这样一个互动:
GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket // Upgrade 头
Connection: Upgrade // 使用 Upgrade 链接
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080
支持 WebSocket 的服务器不会出现通常的 200 状态代码,而是返回类似于以下的输出:
HTTP/1.1 101 Switching Protocols // 协议切换
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp
握手成功后,HTTP 升级请求所依据的 TCP 套接字保持开放,以便客户端和服务器继续发送和接收信息。
关于 WebSockets 如何工作的完整介绍已经超出了本文的范围。请参阅 RFC 6455、HTML5 的 WebSocket 章节,或网络上的许多介绍和教程。
请注意,如果 WebSocket 服务器在 Web 服务器(例如 nginx)后面运行,你可能需要对其进行配置,以便将 WebSocket 升级请求传递给WebSocket 服务器。同样,如果应用程序在云环境中运行,请检查云提供商与 WebSocket 支持有关的说明。
HTTP 与 WebSocket
尽管 WebSocket 被设计为与 HTTP 兼容,并以 HTTP 请求为起点,但必须了解 这两种协议导致了非常不同的架构和应用编程模型。
在 HTTP 和 REST 中,一个应用程序被建模为许多 URL。为了与应用程序进行交互,客户端以请求 - 响应的方式访问这些 URLs。服务器根据 HTTP 的 URL、方法和标头将请求路由到适当的处理器。
相比之下,在 WebSockets 中,通常只有一个 URL 用于初始连接。随后,所有的应用程序消息都在同一个 TCP 连接上流动。这指出了一个完全不同的异步、事件驱动的消息传递架构。
WebSocket 也是一个低级别的传输协议,与 HTTP 不同,它没有为消息内容规定任何语义。这意味着,除非客户端和服务器就消息语义达成一致,否则就没有办法路由或处理消息。
WebSocket 客户端和服务器可以通过 HTTP 握手请求上的 Sec-WebSocket-Protocol
头,协商使用更高级别的消息传输协议(例如 STOMP)。如果没有,他们需要想出自己的约定。
何时使用 WebSockets
WebSockets 可以使一个网页变得动态和互动。然而,在许多情况下,Ajax 和 HTTP 流或长轮询的组合可以提供一个简单而有效的解决方案。
例如,新闻、邮件和社交信息需要动态更新,但每隔几分钟更新一次可能完全没问题。另一方面,协作、游戏和金融应用则需要更接近于实时。
仅仅是延迟并不是一个决定性因素。如果消息量相对较少(例如,监测网络故障),HTTP 流或轮询可以提供一个有效的解决方案。低延迟、高频率和高容量的组合才是使用 WebSocket 的最佳理由。
还请记住,在互联网上,你无法控制的限制性代理可能会排除 WebSocket 的互动,因为它们没有被配置为传递升级标头,或者因为它们关闭了看似闲置的长期连接。这意味着,在防火墙内为内部应用使用 WebSocket 是一个比面向公众的应用更直接的决定。