反向 Ajax,第 1 部分: Comet 简介
简介 Web 开发在过去的几年中有了很大的进展,我们已经远超了把静态网页链接在一起的做法,这种做法会引起浏览器的刷新,并且要等待页面的加载。现在需要的是能够通过 Web 来访问完全动态的应用。 这些应用通常需要尽可能的快,提供近乎实时的组件。在这个分为 5 部分的新系列中,我们学习如何使用反向 Ajax (Reverse Ajax) 技术来开发事件驱动的 Web 应用。 在这第一篇文章中,我们要了解反向 Ajax、轮询 (polling)、流 (streaming)、Comet 和长轮询 (long polling)。学习如何实现不同的反向 Ajax 通信技术,并探讨每种方法的优点和缺点。 您可以下载 本文中例子的相应源代码。 回页首 Ajax、反向 Ajax 和 WebSockets 异步的 JavaScript 和 XML (Ajax),一种可通过 JavaScript 来访问的浏览器功能特性,其允许脚本向幕后的网站发送一个 HTTP 请求而又无需重新加载页面。 Ajax 的出现已经超过了十年,尽管其名字中包含了 XML,但您几乎可以在 Ajax 请求中传送任何的东西。最常使用的数据是 JSON,它与 JavaScript 语法非常接近且消耗更少的带宽。 清单 1清单 1 给出了这样的一个例子,Ajax 请求通过某个地方的邮政编码来检索该地的名称。 清单 1. 清单 1 Ajax 请求示例
在本文 可下载的源代码 中,您可在 listing1.html 中看到这一例子的作用。 反向 Ajax (Reverse Ajax) 本质上则是这样的一种概念:能够从服务器端向客户端发送数据。在一个标准的 HTTP Ajax 请求中,数据是发送给服务器端的,反向 Ajax 可以某些特定的方式来模拟发出一个 Ajax 请求,这些方式本文都会论及,这样的话,服务器就可以尽可能快地向客户端发送事件(低延迟通信)。 WebSocket 技术来自 HTML5,是一种最近才出现的技术,许多浏览器已经支持它(Firefox、Google Chrome、Safari 等等)。WebSocket 启用双向的、全双工的通信信道,其通过某种被称为 WebSocket 握手的 HTTP 请求来打开连接,并用到了一些特殊的报头。连接保持在活动状态,您可以用 JavaScript 来写和接收数据,就像是正在用一个原始的 TCP 套接口一样。WebSocket 会在这一文章系列的第二部分中谈及。 回页首 反向 Ajax 技术 反向 Ajax 的目的是让服务器将信息推送到客户端。Ajax 请求默认情况下是无状态的,且只能从客户端向服务器端发出请求。您可以通过使用技术模拟服务器端和客户端之间的响应式通信来绕过这一限制。 HTTP 轮询和 JSONP 轮询 轮询 (Polling) 涉及了从客户端向服务器端发出请求以获取一些数据,这显然就是一个纯粹的 Ajax HTTP 请求。为了尽快地获得服务器端事件,轮询的间隔(两次请求相隔的时间)必须尽可能地小。但有这样的一个缺点存在:如果间隔减小的话,客户端浏览器就会发出更多的请求,这些请求中的许多都不会返回任何有用的数据,而这将会白白地浪费掉带宽和处理资源。 图 1 图 1 中的时间线说明了客户端发出了某些轮询请求,但没有信息返回这种情况,客户端必须要等到下一个轮询来获取两个服务器端接收到的事件。 图 1. 使用 HTTP 轮询的反向 Ajax JSONP 轮询基本上与 HTTP 轮询一样。不同之处在于使用 JSONP 您可以发送跨域请求(请求不属于您所在的域)。清单1清单 1 使用了 JSONP 来通过邮政编码获取地名。JSONP 请求通常可通过它的回调参数和返回内容识别出来,这些内容是可执行的 JavaScript 代码。 要在 JavaScript 中实现轮询,您可以使用 清单 2. 清单 2 JavaScript 轮询
文章源代码 中的轮询演示给出了轮询方法所消耗的带宽,间隔很小,但可以看到有些请求并未返回事件,清单 3清单 3 给出了这一轮询示例的输出。 清单 3. 清单 3 轮询演示例子的输出
用 JavaScript 实现的轮询的优点和缺点。
Piggyback 捎带轮询 (piggyback polling) 是一种比轮询更加聪明的做法,因为它会删除掉所有非必需的请求(没有返回数据的那些)。不存在时间间隔,客户端在需要的时候向服务器端发送请求。不同之处在于响应的那部分上,响应被分成两个部分:对请求数据的响应和对服务器事件的响应,如果任何一部分有发生的话。图 2图 2 给出了一个例子。 图 2. 使用了 piggyback 轮询的反向 Ajax 在实现 piggyback 技术时,通常针对服务器端的所有 Ajax 请求可能会返回一个混合的响应。文章的下载 中有一个实现示例,如下面的清单 4清单 4 所示。 清单 4. 清单 4 piggyback 代码示例
清单 5清单 5 给出了一些 piggyback 输出。 清单 5. 清单 5 piggyback 输出示例
您可以看到表单验证的结果和附加到响应上的事件。同样,这种方法也有着一些优点和缺点。
回页首 Comet 使用了轮询或是捎带的反向 Ajax 非常受限:其不具伸缩性,不提供低延迟通信(只要事件一到达服务器端,它们就以尽可能快的速度到达浏览器端)。 Comet 是一个 Web 应用模型,在该模型中,请求被发送到服务器端并保持一个很长的存活期,直到超时或是有服务器端事件发生。在该请求完成后,另一个长生存期的 Ajax 请求就被送去等待另一个服务器端事件。使用 Comet 的话,Web 服务器就可以在无需显式请求的情况下向客户端发送数据。 Comet 的一大优点是,每个客户端始终都有一个向服务器端打开的通信链路。服务器端可以通过在事件到来时立即提交(完成)响应来把事件推给客户端,或者它甚至可以累积再连续发送。因为请求长时间保持打开的状态,故服务器端需要特别的功能来处理所有的这些长生存期请求。图 3图 3 给出了一个例子。(本系列的第 2 部分会更详细地解释服务器端的约束条件。) 图 3. 图 3.使用 Comet 的反向 Ajax Comet 的实现可以分成两类:使用流 (streaming) 的那些和使用长轮询 (long polling) 的那些。 回页首 使用 HTTP 流的 Comet 在流 (streaming) 模式中,有一个持久连接会被打开。只会存在一个长生存期请求(图 3图 3 中的 #1),因为每个到达服务器端的事件都会通过这同一连接来发送。因此,客户端需要有一种方法来把通过这同一连接发送过来的不同响应分隔开来。从技术上来讲,两种常见的流技术包括 Forever Iframe(或者 hidden IFrame),或是被用来在 JavaScript 中创建 Ajax 请求的 Forever Iframes Forever Iframe(永存的 Iframe)技术涉及了一个置于页面中的隐藏 Iframe 标签,该标签的
多部分的 第二种技术(更加可靠)是在 清单 6. 清单 6 设置多部分流请求的 JavaScript 代码示例
在服务器端,事情要稍加复杂一些。首先您必须要设置多部分请求,然后挂起连接。清单 7清单 7 展示了如何挂起一个 HTTP 流请求。(本系列的第 3 部分会更加详细地谈及这些 API。) 清单 7. 清单 7 使用 Servlet 3 API 来在 servlet 中挂起一个 HTTP 流请求
现在,每次有事件发生时您都可以遍历所有的挂起连接并向它们写入数据,如清单 8清单 8 所示: 清单 8. 使用 Servlet 3 API 来向挂起的多部分请求发送事件
本文可 下载 文件的 Comet-straming 文件夹中的部分说明了 HTTP 流,在运行例子并打开主页时,您会看到只要事件一到达服务器端,虽然不同步但它们几乎立刻会出现在页面上。而且,如果打开 Firebug 控制台的话,您就能看到只有一个 Ajax 请求是打开的。如果再往下看一些,您会看到 JSON 响应被附在 Response 选项卡中,如图 4图 4 所示: 图 4. HTTP 流请求的 Firebug 视图 照例,做法存在着一些优点和缺点。
回页首 使用 HTTP 长轮询的 Comet 长轮询 (long polling) 模式涉及了打开连接的技术。连接由服务器端保持着打开的状态,只要一有事件发生,响应就会被提交,然后连接关闭。接下来。一个新的长轮询连接就会被正在等待新事件到达的客户端重新打开。 您可以使用 script 标签或是单纯的 script 标签 正如 iframe 一样,其目标是把 script 标签附加到页面上以让脚本执行。服务器端则会:挂起连接直到有事件发生,接着把脚本内容发送回浏览器,然后重新打开另一个 script 标签来获取下一个事件。
回页首
第二种,也是一种推荐的实现 Comet 的做法是打开一个到服务器端的 Ajax 请求然后等待响应。服务器端需要一些特定的功能来允许请求被挂起,只要一有事件发生,服务器端就会在挂起的请求中送回响应并关闭该请求,完全就像是您关闭了 servlet 响应的输出流。然后客户端就会使用这一响应并打开一个新的到服务器端的长生存期的 Ajax 请求,如清单 9清单 9 所示: 清单 9. 清单 9 设置长轮询请求的 JavaScript 代码示例
在后端,代码也是使用 Servlet 3 API 来挂起请求,正如 HTTP 流的做法一样,但是您不需要所有的多部分处理代码。清单 10清单 10 给出了一个例子。 清单 10. 清单 10 挂起一个长轮询 Ajax 请求
在接收到事件时,只是取出所有的挂起请求并完成它们,如清单 11清单 11 所示: 清单 11. 清单 11 在有事件发生时完成长轮询 Ajax 请求
在随带的 下载源代码 中,comet-long-polling 文件夹包含了一个长轮询示例 Web 应用,您可以使用 mvn
回页首 建议 因为所有现代的浏览器都支持跨域资源共享(Cross-Origin Resource Share,CORS)规范,该规范允许XHR执行跨域请求,因此基于脚本的和基于 iframe 的技术已成为了一种过时的需要。 为反向 Ajax 实现和使用 Comet 的最好方法是通过 回页首 结束语 本文提供的是反向 Ajax 技术的一个入门级介绍,文章探索了实现反向 Ajax 通信的不同方法,并说明了每种实现的优势和弊端。您的具体情况和应用需求将会影响到您对最合适方法的选择。不过一般来说,如果您想要在低延迟通信、超时和错误检测、简易性,以及所有浏览器和平台的良好支持这几方面有一个最好的折中的话,那就选择使用了 Ajax 长轮询请求的 Comet。 请继续关注本系列的第 2 部分,该部分将会探讨第三种反向 Ajax 技术:WebSocket。尽管还不是所有的浏览器都支持该技术,但 WebSocket 肯定是一种非常好的反向 Ajax 通信媒介,WebSocket 消除了所有与 HTTP 连接的无状态特性相关的限制。第 2 部分还会谈及由 Comet 和 WebSocket 技术带来的服务器端约束。
http://www.ibm.com/developerworks/cn/views/web/libraryview.jsp?sort_by=&show_abstract=true&show_all=&search_flag=&contentarea_by=Web+development&search_by=%E5%8F%8D%E5%90%91+Ajax+%E9%83%A8%E5%88%86&topic_by=-1&type_by=%E6%89%80%E6%9C%89%E7%B1%BB%E5%88%AB&ibm-search=%E6%90%9C%E7%B4%A2
更多访问 http://www.ibm.com/developerworks/cn/views/web/libraryview.jsp?sort_by=&show_abstract=true&show_all=&search_flag=&contentarea_by=Web+development&search_by=%E5%8F%8D%E5%90%91+Ajax+%E9%83%A8%E5%88%86&topic_by=-1&type_by=%E6%89%80%E6%9C%89%E7%B1%BB%E5%88%AB&ibm-search=%E6%90%9C%E7%B4%A2 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |