Spring MVC 3.2 预览:实时更新技术
上次更新于 2012 年 11 月 5 日(Spring MVC 3.2 RC1)
在我的上一篇博文中,我介绍了Spring MVC 3.2 中基于 Servlet 3 的新异步支持,并讨论了长时间运行的请求。异步处理的第二个非常重要的动机是浏览器需要接收实时更新。示例包括在浏览器中聊天、股票报价、状态更新、实时体育结果等。当然,并非所有示例都同样对延迟敏感,但它们都具有类似的需求。
在标准的 HTTP 请求-响应语义中,浏览器发起请求,服务器发送响应,这意味着服务器在收到浏览器的请求之前无法发送新信息。已经发展出几种方法,包括传统轮询、长轮询和HTTP 流式传输,最近我们还有WebSocket协议。
传统轮询
浏览器不断发送请求以检查是否有新信息,服务器每次都会立即响应。这适合可以以相当稀疏的间隔进行轮询的场景。例如,邮件客户端可以每 10 分钟检查一次新邮件。它很简单,而且有效。但是,当需要尽快显示新信息时,这种方法效率低下,在这种情况下,轮询必须非常频繁。
长轮询
浏览器不断发送请求,但服务器只有在有新信息要发送时才会响应。从客户端的角度来看,这与传统轮询相同。从服务器的角度来看,这非常类似于长时间运行的请求,并且可以使用第 1 部分中讨论的技术进行扩展。
响应可以保持打开多长时间?浏览器设置为在 5 分钟后超时,而代理等网络中介可能更早超时。因此,即使没有新的信息到达,长轮询请求也应该定期完成,以允许浏览器发送新的请求。这IETF 文档建议使用 30 到 120 秒之间的超时值,但要使用的实际值可能取决于您对将浏览器与服务器分隔开的网络中介的控制程度。
长轮询可以显著减少接收低延迟信息更新所需的请求数量,尤其是在新信息以不规则间隔出现的情况下。但是,更新越频繁,它就越接近传统轮询。
HTTP 流式传输
浏览器向服务器发送请求,服务器在有信息要发送时响应。但是,与长轮询不同,服务器会保持响应打开,并在新更新到达时继续发送更多更新。这种方法消除了轮询的需要,但也与典型的 HTTP 请求-响应语义有更大的偏差。例如,客户端和服务器需要就如何解释响应流达成一致,以便客户端知道一个更新在哪里结束,另一个更新在哪里开始。此外,网络中介可以缓存响应流,从而破坏了这种方法的意图。这就是今天更常使用长轮询的原因。
WebSocket 协议
浏览器向服务器发送 HTTP 请求以切换到 WebSocket 协议,服务器通过确认升级来响应。此后,浏览器和服务器可以在 TCP 套接字上双向发送数据帧。
WebSocket 协议旨在取代轮询的需要,并且特别适用于浏览器和服务器之间需要高频率交换消息的场景。通过 HTTP 的初始握手确保 WebSocket 请求可以穿过防火墙。但是,也存在重大挑战,因为大多数已部署的浏览器不支持 WebSockets,并且在通过网络中介方面存在更多问题。
WebSockets 围绕文本或二进制消息的双向交换展开。它导致了一种与基于 RESTful 的 HTTP 架构明显不同的方法。实际上,需要在 WebSockets 之上使用另一种协议,例如 XMPP、AMQP、STOMP 或其他协议,哪些协议将成为主流还有待观察。
该WebSocket 协议已经由 IETF 标准化,而WebSocket API处于由 W3C 标准化的最后阶段。许多 Java 实现已经可用,包括 Jetty 和 Tomcat 等 servlet 容器。Servlet 3.1 规范可能会支持初始 WebSocket 升级请求,而单独的JSR-356将定义基于 Java 的 WebSocket API。
回到 Spring MVC 3.2,Servlet 3 异步功能可用于长时间运行的请求以及 HTTP 流式传输,Filip Hanik称之为“客户端 AJAX 调用的服务器版本”。至于 WebSockets,Spring 3.2 中尚不支持,但很可能包含在 Spring 3.3 中。您可以关注SPR-9356以获取进度更新。
下一篇文章转向示例代码,并更详细地解释了新的 Spring MVC 3.2 功能。