反向Ajax 30分钟快速掌握

场景1:当有新邮件的时候,网页自动弹出提示信息而无需用户手动的刷新收件箱。

场景2:当用户的手机扫描完成页面中的二维码以后,页面会自动跳转。

场景3:在类似聊天室的环境中有任何人发言,所有登录用户都可以即时看见信息。

与传统的MVC模型请求必须从客户端发起由服务器响应相比,使用反向Ajax能够模拟服务器端主动向客户端推送事件从而提高用户体验。本文将分两个部分讨论反向Ajax技术,包括:Comet和WebSocket。文章旨在演示如何实现以上两种技术手段,Struts2或SpringMVC中的应用并未涉及。此外,Servlet的配置也采用注解的方式,相关知识大家可以参考其它资料。

一、Comet(最佳的兼容手段)

Comet本质上则是这样的一种概念:能够从服务器端向客户端发送数据。在一个标准的 HTTP Ajax 请求中,数据是发送给服务器端的,反向 Ajax 以某些特定的方式来模拟发出一个 Ajax 请求,这样的话,服务器就可以尽可能快地向客户端发送事件。由于普通HTTP请求往往会伴随页面的跳转,而推送事件则需要浏览器停留在同一个页面或者框架下,因此Comet的实现只能够通过Ajax来完成。

它的实现过程如下:页面加载的时候随即向服务器发送一条Ajax请求,服务器端获取请求并将它保存在一个线程安全的容器中(通常为队列)。同时服务器端仍然可以正常响应其他请求。当需要推送的事件到来的时候,服务器遍历容器中的请求在返回应答后删除。于是所有停留在页面中的浏览器都会获得该应答,并再次发送Ajax请求,重复上述过程。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html> <html lang="en"> <base href="<%=basePath%>"> <head> <title>WebSocket</title> <script type="text/javascript" src="static/jquery-1.9.1.min.js"></script> <script type="text/javascript"> $(function() { connect(); $("#btn").click(function() { var value = $("#message").val(); $.ajax({ url : "longpolling?method=onMessage&msg=" + value, cache : false, dataType : "text", success : function(data) { } }); }); }); function connect() { $.ajax({ url : "longpolling?method=onOpen", cache : false, dataType : "text", success : function(data) { connect(); alert(data); } }); } </script> </head> <body> <h1>LongPolling</h1> <input type="text" id="message" /> <input type="button" id="btn" value="发送" /> </body> </html>

我们注意到,由btn发送的请求其实并不需要获取应答。整个过程的关键是需要客户端始终让服务器保持connect()的请求。而服务器端首先需要支持这种异步的响应方式,幸运的是目前为止绝大部分的Servlet容器都已经提供了良好的支持。下面以Tomcat为例:

package servlet; import java.io.IOException; import java.io.PrintWriter; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(value="/longpolling", asyncSupported=true) public class Comet extends HttpServlet { private static final Queue<AsyncContext> CONNECTIONS = new ConcurrentLinkedQueue<AsyncContext>(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getParameter("method"); if (method.equals("onOpen")) { onOpen(req, resp); } else if (method.equals("onMessage")) { onMessage(req, resp); } } private void onOpen(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { AsyncContext context = req.startAsync(); context.setTimeout(0); CONNECTIONS.offer(context); } private void onMessage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String msg = req.getParameter("msg"); broadcast(msg); } private synchronized void broadcast(String msg) { for (AsyncContext context : CONNECTIONS) { HttpServletResponse response = (HttpServletResponse) context.getResponse(); try { PrintWriter out = response.getWriter(); out.print(msg); out.flush(); out.close(); context.complete(); CONNECTIONS.remove(context); } catch (IOException e) { e.printStackTrace(); } } } }

ConcurrentLinkedQueue是Queue队列的一个线程安全实现,这里使用它来作为保存请求的容器。AsyncContext是Tomcat支持的异步环境,不同的服务器使用的对象也略有不同。Jetty支持的对象是Continuation。完成了广播的请求需要通过context.complete()将相关请求结束,并使用CONNECTIONS.remove(context)删除队列。

二、WebSocket(来自HTML5的支持)

使用 HTTP 长轮询的 Comet 是可靠地实现反向 Ajax 的最佳方式,因为现在所有浏览器都提供了这方面的支持。

WebSockets 在 HTML5 中出现,是比 Comet 更新的反向 Ajax 技术。WebSockets 支持双向、全双工通信信道,而且许多浏览器(Firefox、Google Chrome 和 Safari)也支持它。连接通过 HTTP 请求(也称为 WebSockets 握手)和一些特殊的标头 (header)。连接一直处于激活状态,您可以用 JavaScript 编写和接收数据,正如您使用原始 TCP 套接字一样。

通过输入 ws:// 或 wss://(在 SSL 上)启动 WebSocket URL。如图:

首先:WebSockets并非在所有浏览器上都能获得良好的支持,显然IE又拖了后腿。因此当你打算使用这项技术之前必须考虑到用户的使用环境,如果你的项目面向的是互联网或者包括手机端用户,奉劝大家三思。

其次:WebSockets提供的请求区别于普通的HTTP请求,它是一种全双工通信且始终处于激活状态(如果你不去关闭它的话)。这就意味着你不用每次获得应答后再次向服务器发送请求,这样可以节约大量的资源。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; String ws = "ws://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html> <html lang="en"> <base href="<%=basePath%>"> <head> <title>WebSocket</title> <script type="text/javascript" src="static/jquery-1.9.1.min.js"></script> <script type="text/javascript"> $(function() { var websocket = null; if ("WebSocket" in window){ websocket = new WebSocket("<%=ws%>websocket"); } else { alert("not support"); } websocket.onopen = function(evt) { } websocket.onmessage = function(evt) { alert(evt.data); } websocket.onclose = function(evt) { } $("#btn").click(function() { var text = $("#message").val(); websocket.send(text); }); }); </script> </head> <body> <h1>WebSocket</h1> <input type="text" id="message" /> <input type="button" id="btn" value="发送"/> </body> </html>

JQuery对WebSocket还未提供更良好的支持,因此我们必须使用Javascript来编写部分代码(好在并不复杂)。并且打部分常见的服务器都可以支持ws请求,以Tomcat为例。在6.0版本中WebSocketServlet对象已经被标注为@java.lang.Deprecated,7.0以后的版本支持jsr365提供的实现,因此你必须使用注解来完成相关配置。

package servlet; import java.io.IOException; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/websocket") public class WebSocket { private static final Queue<WebSocket> CONNECTIONS = new ConcurrentLinkedQueue<WebSocket>(); private Session session; @OnOpen public void onOpen(Session session) { this.session = session; CONNECTIONS.offer(this); } @OnMessage public void onMessage(String message) { broadcast(message); } @OnClose public void onClose() { CONNECTIONS.remove(this); } private synchronized void broadcast(String msg) { for (WebSocket point : CONNECTIONS) { try { point.session.getBasicRemote().sendText(msg); } catch (IOException e) { CONNECTIONS.remove(point); try { point.session.close(); } catch (IOException e1) { } } } } }

三、总结(从请求到推送)

在传统通信方案中,如果系统 A 需要系统 B 中的信息,它会向系统 B 发送一个请求。系统 B 将处理请求,而系统 A 会等待响应。处理完成后,会将响应发送回系统 A。在同步 通信模式下,资源使用效率比较低,这是因为等待响应时会浪费处理时间。

在异步 模式下,系统 A 将订阅它想从系统 B 中获取的信息。然后,系统 A 可以向系统 B 发送一个通知,也可以立即返回信息,与此同时,系统 A 可以处理其他事务。这个步骤是可选的。在事件驱动应用程序中,通常不必请求其他系统发送事件,因为您不知道这些事件是什么。在系统 B 发布响应之后,系统 A 会立即收到该响应。

Web 框架过去通常依赖传统 “请求-响应” 模式,该模式会导致页面刷新。随着 Ajax、Reverse Ajax 以及 WebSocket 的出现,现在可以将事件驱动架构的概念轻松应用于 Web,获得去耦合、可伸缩性和反应性 (reactivity) 等好处。更良好的用户体验也会带来新的商业契机。

以上所述是小编给大家介绍的反向Ajax 30分钟快速掌握,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

时间: 2024-07-29 15:27:33

反向Ajax 30分钟快速掌握的相关文章

反向Ajax 30分钟快速掌握_AJAX相关

场景1:当有新邮件的时候,网页自动弹出提示信息而无需用户手动的刷新收件箱. 场景2:当用户的手机扫描完成页面中的二维码以后,页面会自动跳转. 场景3:在类似聊天室的环境中有任何人发言,所有登录用户都可以即时看见信息. 与传统的MVC模型请求必须从客户端发起由服务器响应相比,使用反向Ajax能够模拟服务器端主动向客户端推送事件从而提高用户体验.本文将分两个部分讨论反向Ajax技术,包括:Comet和WebSocket.文章旨在演示如何实现以上两种技术手段,Struts2或SpringMVC中的应用

OSS移动开发实战1 (30分钟快速搭建基于OSS的移动应用)

30分钟快速搭建移动应用直传服务 背景 这是一个移动互联的时代.手机APP上传的数据会越来越多.把数据存储的问题交给OSS, 让开发者能更加专注于自己的应用逻辑. 那么怎么样基于OSS构建一个APP存储系统呢? 目的 本教程就是让你在30分钟内搭建一个基于OSS的移动应用数据直传服务,所谓直传就是移动应用的数据的上传和下载直接直连OSS,只有控制流走用户自己的服务器. 安全的上传下载方式(临时,灵活的赋权鉴权), 成本低(这样用户不需要准备很多服务器,因为移动应用直联云存储,只有控制流走用户自己

OSS移动开发实战2 (30分钟快速搭建移动应用上传回调服务)

30分钟快速搭建移动应用上传回调服务 背景 上一篇文章我们介绍了如何快速搭建移动应用 参考移动端开发场景流程图点击查看 上述图中Android/iOS移动应用的职责 会负责申请STS凭证,然后使用从应用服务器取的凭证上传 上述图中应用服务器的职责 负责给Android/iOS移动应用,生成STS凭证 上述图中OSS的职责 OSS负责处理移动应用的数据请求 问题 对于Android/iOS移动应来说,移动应用只需要执行操作1(申请STS凭证),就能调用多次5(使用该STS凭证上传数据到OSS).这

用云存储30分钟快速搭建APP

背景 不管你承认与否,移动互联的时代已经到来,这是一个移动互联的时代,手机已经是当今世界上引领潮流的趋势,大型的全球化企业和中小企业都把APP程序开发纳入到他们的企业发展策略当中. 但随着手机APP上传的数据会越来越多,任何企业系统.应用的软件都必须解决这一问题,数据存储必须以某种方式保存,不能丢失并且能够有效简单地使用和更新这些数据.如果开发者自行解决数据存储的问题,有可能在后期花费在之上的精力是其他方面的数倍,但是如果将数据存储这一问题交给OSS,那么开发者就可以从中得以解放,更加专注于自己

Fuel 30 分钟快速安装OpenStack(图文教程)_OpenStack

一直以来,对于openstack 的初学者来讲,安装往往是入门的头大难题.在E版本之前,要搭建一个基本能用的openstack 环境那是相当麻烦,自己要装机,自己搞源,自己照着文档敲命令,又没有靠谱的文档,官方给出的文档依旧有好多坑,还有语言问题往往用上好几天时间都装不起来,慢慢地就丧失了学习openstack 的信心! 不过后来情况有了很大改观,从E版本开始,以后安装过程简化许多,文档质量提高不少.尽管如此对于初学者还讲还是比较复杂,其实很多时候,很多人只是想体会一下openstack,完全不

OSS移动开发实战3 (30分钟快速搭建移动应用之安全策略)

搭建应用服务器之STS Policy 上一篇文章中介绍了如何快速搭建应用服务器,在本文中会基于上文提到的应用服务器,以上海的Bucket app-base-oss为例子,配置不同的Policy以实现不同的权限控制. 以下说明中假设你已经开通了STS,并完全阅读了上一篇文章.以下提到的Policy都是指上文提到的config.json中指定的Policy文件的内容. 以下讲述的获取STS Token 后对OSS操作指的是应用服务器指定Policy,从STS获取临时凭证后,应用通过临时凭证访问OSS

30分钟快速打造一个完善的直播聊天系统

下面的代码基于高性能的通信王牌工具 Netty.我们将一些实际场景都添加进去,比如用户身份的验证,游客只能浏览不能发言,多房间(频道)的聊天. 这篇文章非常适合和我一样的 Java 新手,适合作为学习 Java 的切入点,不需要考虑tomcat.spring.mybatis等.唯一的知识点就是 maven 的基础使用. 完整的代码地址 https://github.com/zhoumengkang/netty-websocket 项目结果如下 ├── WebSocketServer.java 启

30分钟学会正则表达式基础教程

基础教程|教程|正则表达式|正则 目录 本文目标 如何使用本教程 正则表达式到底是什么? 入门 测试正则表达式 元字符 字符转义 重复 字符类 反义 替换 分组 后向引用 零宽断言 负向零宽断言 注释 贪婪与懒惰 处理选项 平衡组/递归匹配 还有些什么东西没提到 联系作者 最后,来点广告... 一些我认为你可能已经知道的术语的参考 网上的资源及本文参考文献 更新说明 本文目标 30分钟内让你明白正则表达式是什么,并对它有一些基本的了解,让你可以在自己的程序或网页里使用它. 如何使用本教程 最重要

30分钟正则表达式指导

正则 by Jim Hollenhorst  译 寒带鱼 你是否曾经想过正则表达式是什么,怎样能够快速得到对它的一个基本的认识?我的目的就是在30分钟内带你入门并且对正则表达式有一个基本的理解.事实是正则表达式并没有它看起来那么复杂.学习它最好的办法就是开始写正则表达式并且不断实践.在最初的30分钟之后,你就应该知道一些基本的结构并且有能力在你的程序或者web页面中设计和使用正则表达式了.对那些想要深入研究的人,现在已经有很多非常好的可用资源来让你更深入的学习. 到底什么是正则表达式? 我相信你