本来只是想梳理以下Servlet 3.0异步请求,不曾想涉及到Comet(维基百科上面对
comet有具体的定义和介绍),篇章多了起来,对以往所学习和心得,重新梳理一下。
Comet的实现主要流(streaming) 形式和长轮询(long polling)两种形式。流和长轮询区别主要在于,在一次连接中,服务器端推送多次的数据为流,只推送一次为长轮询。
流推送(Comet Streaming)
Comet流推送目前一般采用:
- 隐藏IFrame(Hidden iframe)
服务器端一般会输出一段javascript脚本 <script>comet.showMsg(“这是新的消息”)</script>
好处在于各个浏览器都支持iframe,目前在IE、Firefox下面效果最好,页面不再显示正在加载中的讨厌的提示(见Servlet 3.0笔记之异步请求Comet推送iFrame示范) - XMLHttpRequest
很可怜,目前支持情况最好的是火狐浏览器、IE8以及Safari
参考文章:
Servlet 3.0笔记之异步请求Comet推送XMLHttpRequest示范
Servlet 3.0笔记之异步请求Comet流推送(Streaming)实现小结。
长轮询(Ajax with long polling)
客户端会与服务器建立一个持久的连接,直到服务器端有数据发送过来(超时也会发送数据),双方断开连接,客户端处理完推送的数据,会再次发起一个持久的连接,循环往复。其实现形式:
- XHR方式长轮询(XMLHttpRequest long polling)
服务器端可以返回原始的数据,也可以返回格式化的JSON、XML、JAVASCRIPT信息,相比iframe形式流推送,更自由一些。使用形式和传统意义上的AJAX GET方式大致一样,只不过下一次的轮询需要等到有数据返回处理完方可。
默认不支持跨域,实践中会打折扣。 - JAVASCRIPT标签轮询(Script tag long polling)
可能翻译不太准确,主要使用类似于如下形式: <script src='js/yourCometProvider.js' type='text/javascript'></script>
使用跨域的JS脚本,可能会有安全方面隐患,或许这个间接风险是可控的。
也可以使用JSONP用以规避这个风险。
进阶阅读:Comet (long polling) for all browsers using ScriptCommunicator
代码写的很巧妙,也很简短,思路不错,推荐一看。
参考文章:
Servlet 3.0笔记之异步请求Comet推送长轮询(long polling)篇
Servlet 3.0笔记之异步请求Comet推送长轮询(long polling)篇补遗
Comet浏览器支持汇总
大致总结一下各个浏览器对Comet支持大致情况,可能不太科学,仅以自己实践中感知为准。table{border:1px solid #888888;border-collapse:collapse;font-family:Arial,Helvetica,sans-serif;margin-top:10px;width:100%;}table th {background-color:#CCCCCC;border:1px solid #888888;padding:5px 15px 5px 5px;text-align:left;vertical-align:baseline;}table td {background-color:#EFEFEF;border:1px solid #AAAAAA;padding:5px 15px 5px 5px;vertical-align:text-top;}
浏览器 | 流(streaming) | 长轮询(long polling) |
IE(6-8) | htmlfile + iframe 支持流形式; IE8的XDomainRequest支持HTTP Streaming | 支持脚本加载事件;页面表现完美 |
Firefox(3.5) | 支持XMLHttpRequest Streaming 和隐藏的IFrame组件 | 支持脚本文件async属性;页面表现完美 |
Chrome(>9.0) | 不支持XMLHttpRequest Streaming;使用IFrame会一直出现正在加载中图标 | 支持脚本文件async属性;页面表现完美 |
Safari(5) | 浏览器支持XMLHttpRequest Streaming | 支持脚本文件的async属性;页面表现完美 |
Opera(>9.0) | 不支持XMLHttpRequest Streaming,使用IFrame的话会一样会出现正在加载中的标志 | 本机测试脚本文件长轮询时间若长于20秒,则会出现连接中断情况;会出现正在加载中的标志 |
Servlet 3.0 支持
长轮询或流推送,相对于Servlet 3.0 异步请求,相差不大,都需要定义一个连接超时时间,但后者可以向客户端推送多次,前者推送一次之后需要立刻断开了与客户端的连接;在超时事件发生后,都可以通知客户端超时已发生。另外在高并发环境下可能需要做多层次的消息路由服务以降低单机的处理极限。实践中使用Comet流推送,也需要在一定的时间后再次重连,或许可以称之为流轮询(streaming poll),只是人们没有提起而已。
Comet为发布/订阅模型在前端应用的一种变形。可以很直观的将服务器端视为内容发布者,浏览器端为订阅者。相对于谷歌的pubsubhubbub协议,区别在于Comet使用HTTP 1.1 长连接协议,客户端为浏览器,没有公开的可回调的客户端地址。而pubsubhubbub则要求订阅者有一个可以回调的URL地址(这个URL对于发布者服务器是直达的),一旦有新的可用数据,可以推送到客户端,客户端某个URL监听就是。双方在用途、使用环境上不相同,需要区别对待。
话说观察者模式在实际应用中十分广泛,变体也很多。
参考资料: