WebSocket

参考文档的这一部分涵盖了对 Servlet 栈、WebSocket 消息传递(包括原始 WebSocket 交互)、通过 SockJS 进行 WebSocket 模拟以及通过 STOMP 作为 WebSocket 子协议进行发布-订阅消息传递的支持。

WebSocket 简介

WebSocket 协议,RFC 6455,提供了一种标准化的方式,可以在客户端和服务器之间通过单个 TCP 连接建立全双工、双向通信通道。它与 HTTP 不同,是一种不同的 TCP 协议,但设计为可以在 HTTP 上工作,使用端口 80 和 443,并允许重复使用现有的防火墙规则。

WebSocket 交互以使用 HTTP Upgrade 标头升级或在这种情况下切换到 WebSocket 协议的 HTTP 请求开始。以下示例显示了这种交互

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: https://127.0.0.1:8080
1 Upgrade 标头。
2 使用Upgrade 连接。

而不是通常的 200 状态代码,支持 WebSocket 的服务器返回类似于以下内容的输出

HTTP/1.1 101 Switching Protocols (1)
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp
1 协议切换

成功握手后,HTTP 升级请求的基础 TCP 套接字保持打开状态,以便客户端和服务器继续发送和接收消息。

本文档不包含有关 WebSockets 工作原理的完整介绍。请参阅 RFC 6455、HTML5 的 WebSocket 章节或网络上的众多介绍和教程。

请注意,如果 WebSocket 服务器运行在 Web 服务器(例如 nginx)后面,则可能需要将其配置为将 WebSocket 升级请求传递到 WebSocket 服务器。同样,如果应用程序在云环境中运行,请检查云提供商与 WebSocket 支持相关的说明。

HTTP 与 WebSocket

即使 WebSocket 被设计为与 HTTP 兼容并以 HTTP 请求开始,但了解这两种协议会导致非常不同的架构和应用程序编程模型也很重要。

在 HTTP 和 REST 中,应用程序被建模为许多 URL。为了与应用程序交互,客户端以请求-响应的方式访问这些 URL。服务器根据 HTTP URL、方法和标头将请求路由到相应的处理程序。

相反,在 WebSockets 中,通常只有一个 URL 用于初始连接。随后,所有应用程序消息都流经同一 TCP 连接。这指向了一种完全不同的异步、事件驱动、消息传递架构。

WebSocket 也是一种低级传输协议,与 HTTP 不同,它不规定消息内容的任何语义。这意味着,除非客户端和服务器就消息语义达成一致,否则无法路由或处理消息。

WebSocket 客户端和服务器可以通过 HTTP 握手请求上的Sec-WebSocket-Protocol 标头协商使用更高级别的消息传递协议(例如 STOMP)。在没有此标头的情况下,他们需要制定自己的约定。

何时使用 WebSockets

WebSockets 可以使网页变得动态和交互式。但是,在许多情况下,AJAX 和 HTTP 流或长轮询的组合可以提供一个简单有效的解决方案。

例如,新闻、邮件和社交信息流需要动态更新,但每隔几分钟更新一次可能完全可以。另一方面,协作、游戏和金融应用程序需要更接近实时。

仅延迟不是决定因素。如果消息量相对较低(例如,监视网络故障),HTTP 流或轮询可以提供有效的解决方案。正是低延迟、高频率和高容量的组合使 WebSocket 成为最佳选择。

还要记住,在互联网上,您无法控制的限制性代理可能会阻止 WebSocket 交互,这是因为它们未配置为传递Upgrade 标头,或者因为它们关闭了看起来空闲的长期连接。这意味着,在防火墙内部使用 WebSocket 进行内部应用程序的决策比面向公众的应用程序更容易。