- 作者简介
- 内容提要
- 关于本书
- 路线图
- 代码规范与下载
- 作者在线
- 封面插图简介
- 前言
- 译者序
- 致谢
- 第1部分 Spring 的核心
- 第1章 Spring 之旅
- 第2章 装配 Bean
- 第3章 高级装配
- 第4章 面向切面的 Spring
- 第2部分 Web 中的 Spring
- 第5章 构建 Spring Web 应用程序
- 第6章 渲染 Web 视图
- 第7章 Spring MVC 的高级技术
- 第8章 使用 Spring Web Flow
- 第9章 保护 Web 应用
- 第3部分 后端中的 Spring
- 第10章 通过 Spring 和 JDBC 征服数据库
- 第11章 使用对象-关系映射持久化数据
- 第12章 使用 NoSQL 数据库
- 第13章 缓存数据
- 第14章 保护方法应用
- 第4部分 Spring 集成
- 第15章 使用远程服务
- 第16章 使用 Spring MVC 创建 REST API
- 第17章 Spring消息
- 第18章 使用 WebSocket 和 STOMP 实现消息功能
- 第19章 使用 Spring 发送 Email
- 第20章 使用 JMX 管理 Spring Bean
- 第21章 借助 Spring Boot 简化 Spring 开发
18.2 应对不支持 WebSocket 的场景
WebSocket是一个相对比较新的规范。虽然它早在2011年底就实现了规范化,但即便如此,在Web浏览器和应用服务器上依然没有得到一致的支持。Firefox和Chrome早就已经完整支持WebSocket了,但是其他的一些浏览器刚刚开始支持WebSocket。如下列出了几个流行的浏览器支持WebSocket功能的最低版本:
Internet Explorer:10.0
Firefox: 4.0(部分支持),6.0(完整支持)。
Chrome: 4.0(部分支持),13.0(完整支持)。
Safari: 5.0(部分支持),6.0(完整支持)。
Opera: 11.0(部分支持),12.10(完整支持)。
iOS Safari: 4.2(部分支持),6.0(完整支持)。
Android Browser: 4.4。
令人遗憾的是,很多的网上冲浪者并没有认识到或理解新Web浏览器的特性,因此升级很慢。另外,有的公司规定使用特定版本的浏览器,这样它们的员工很难(或不可能)使用更新的浏览器。鉴于这些情况,如果你的应用程序使用WebSocket的话,用户可能会无法使用。
服务器端对WebSocket的支持也好不到哪里去。GlassFish在几年前就开始支持一定形式的WebSocket,但是很多其他的应用服务器在最近的版本中刚刚开始支持WebSocket。例如,我在测试上述例子的时候,所使用的就是Tomcat 8的发布候选构建版本。
即便浏览器和应用服务器的版本都符合要求,两端都支持WebSocket,在这两者之间还有可能出现问题。防火墙代理通常会限制所有除HTTP以外的流量。它们有可能不支持或者(还)没有配置允许进行WebSocket通信。
在当前的WebSocket领域,我也许描述了一个很阴暗的前景。但是,不要因为这一些不支持,你就停止使用WebSocket的功能。当它能够正常使用的时候,WebSocket是一项非常棒的技术,但是如果它无法得到支持的话,我们所需要的仅仅是一种备用方案(fallback plan)。
幸好,提到WebSocket的备用方案,这恰是SockJS所擅长的。SockJS是WebSocket技术的一种模拟,在表面上,它尽可能对应WebSocket API,但是在底层它非常智能,如果WebSocket技术不可用的话,就会选择另外的通信方式。SockJS会优先选用WebSocket,但是如果WebSocket不可用的话,它将会从如下的方案中挑选最优的可行方案:
XHR流。
XDR流。
iFrame事件源。
iFrame HTML文件。
XHR轮询。
XDR轮询。
iFrame XHR轮询。
JSONP轮询。
好消息是在使用SockJS之前,我们并没有必要全部了解这些方案。SockJS让我们能够使用统一的编程模型,就好像在各个层面都完整支持WebSocket一样,SockJS在底层会提供备用方案。
例如,为了在服务端启用SockJS通信,我们在Spring配置中可以很简单地要求添加该功能。重新回顾一下程序清单18.2中的registerWebSocketHandlers()方法,稍微加一点内容就能启用SockJS:
addHandler()方法会返回WebSocketHandlerRegistration,通过简单地调用其withSockJS()方法就能声明我们想要使用SockJS功能,如果WebSocket不可用的话,SockJS的备用方案就会发挥作用。
如果你使用XML来配置Spring的话,启用SockJS只需在配置中添加<websocket:sockjs>元素即可:
要在客户端使用SockJS,需要确保加载了SockJS客户端库。具体的做法在很大程度上依赖于使用JavaScript模块加载器(如require.js或curl.js)还是简单地使用<script>标签加载JavaScript库。加载SockJS客户端库的最简单办法是使用<script>标签从SockJS CDN中进行加载,如下所示:
用WebJars解析Web资源
在我的样例代码中,使用了WebJars来解析JavaScript库,使其作为项目Maven或Gradle构建的一部分,就像其他的依赖一样。为了支持该功能,我在Spring MVC配置中搭建了一个资源处理器,让它负责解析路径以“/webjars/**”开头的请求,这也是WebJars的标准路径:
在这个资源处理器准备就绪后,我们可以在Web页面中使用如下的<script>标签加载SockJS库:
注意,这个特殊的<script>标签来源于一个Thymeleaf模板,并使用“@{...}”表达式来为JavaScript文件计算完整的相对于上下文的URL路径。
除了加载SockJS客户端库以外,在程序清单18.4中,要使用SockJS只需修改两行代码:
所做的第一个修改就是URL。SockJS所处理的URL是“http://”或“https://”模式,而不是“ws://”和“wss://”。即便如此,我们还是可以使用相对URL,避免书写完整的全限定URL。在本例中,如果包含JavaScript的页面位于“http://localhost:8080/websocket”路径下,那么给定的“marco”路径将会形成到“http://localhost:8080/websocket/marco”的连接。
但是,这里最核心的变化是创建SockJS实例来代替WebSocket。因为SockJS尽可能地模拟了WebSocket,所以程序清单18.4中的其他代码并不需要变化。相同的onopen、onmessage和onclose事件处理函数用来响应对应的事件,相同的send()方法用来发送“Marco!”到服务器端。
我们并没有改变很多的代码,但是客户端-服务器之间通信的运行方式却有了很大的变化。我们可以完全相信客户端和服务器之间能够进行类似于WebSocket这样的通信,即便浏览器、服务器或位于中间的代理不支持WebSocket,我们也无需再担心了。
WebSocket提供了浏览器-服务器之间的通信方式,当运行环境不支持WebSocket的时候,SockJS提供了备用方案。但是不管哪种场景,对于实际应用来说,这种通信形式都显得层级过低。让我们看一下如何在WebSocket之上使用STOMP(Simple Text Oriented Messaging Protocol),为浏览器-服务器之间的通信增加恰当的消息语义。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论