一、 Ajax技术简介
Ajax这个概念的最早提出者Jesse James Garrett认为Ajax是Asynchronous JavaScript and XML的缩写,他认为Ajax并不是一种新的语言或技术,它实际上是以下几种技术以一种强大的方式糅合在一起,各自发挥自己的所长:
1.使用XHTML和CSS实现基于标准化的数据表示;
2.使用DOM实现动态显示和交互;
3.使用XML和XSLT进行数据交换与处理;
4.使用XMLHttpRequest与服务器进行异步通信;
5.使用JavaScript绑定和处理所有数据;
笔者认为,Ajax这个概念可以扩展一下,允许浏览器与服务器进行异步通信而无需全部刷新当前页面的技术都可以包含在Ajax的技术范畴之内。
图1 传统Web应用模型(左)与Ajax应用模型(右)的对比
如图1所示,传统的Web应用模型通常是用户在页面上做一些操作(如点击一个按钮),浏览器将触发一个HTTP请求到后台的Web服务器,后台服务器接受到HTTP请求后就开始做出相应处理,如从数据库提取数据,访问其他异构的应用系统等,然后返回一个HTML页面到浏览器,浏览器将返回的页面呈现给用户,这种模型中页面与服务器之间的通信是同步的。 这样做的好处在此不赘述,这里说说这种模型的缺点,那就是当服务器在处理HTTP请求的时候,用户只能被动地等待处理的结束,尤其当服务器需要很长时间处理HTTP请求时,用户将会因为需要等待很长的时间而对网站失去兴趣,这对一个商业网站来讲意味着吸引不到新用户或者已有用户群的流失,影响是致命的。
Ajax应用模型的出现就是为了避免传统Web应用模型的不足。 Ajax应用模型在页面和服务器之间增加了—个中间层, 叫作Ajax引擎,它使得页面与服务器可以进行异步通信。页面将请求发送给Ajax引擎,由后者来负责与服务器的通信,与此同时用户依然可以在页面上做其他的操作,无需等待服务器的返回,一旦服务器返回,将由Ajax引擎来提取返回的数据并更新页面上需要更新的局部区域。图2展示了传统Web应用模型和Ajax应用模型的服务器通信机制。
图2 传统Web应用同步通信(上)与Ajax异步通信(下)的对比
但是,Ajax应用模型并不会取代传统Web应用模型。这是因为,有时用户的操作需要更新整个页面,传统的Web应用模型适用于这种情形;多数情况下,用户的操作只需要更新页面上一小部分区域,这时Ajax应用模型可以派上用场。除此之外,Ajax本身的缺点也使其不能用于Web应用的所有场景。
二、 Ajax与RIA
RIA是Rich Internet Application的缩写,是具有丰富用户接口和用户体验的Web应用程序的统称,其宗旨是为用户提供像桌面应用程序一样的丰富体验。目前存在Applet、 Flash、XUL、XAML、Flex和Laszlo等RIA解决方案。
Applet是Sun公司开发的基于Java的小应用程序,利用AWT或Swing来构建用户界面,与桌面应用程序没有区别, Applet能够嵌入到网页中运行。缺点是需要客户端安装JRE,而且有着Swing和AWT固有的交互性不好的缺点。
Flash是Macromedia公司最早用来制作网页动画的解决方案,后来加入丰富的ActionScript脚本语言,能够创建高度交互的动态Web应用。浏览Flash的网页只需要客户端装有Flash播放器就可以,而且Flash播放器相对JRE占用磁盘空间小得多。缺点是开发Flash的工具比较昂贵。
XUL是指XML用户界面语言(XML User Interface Language),由Mozilla基金会推出,流行的Firefox浏览器和Thunderbird邮件客户端都是由XUL编写的,利用XUL,开发人员可以创建很丰富的应用,这个应用可以与Internet连接,也可以不连接。其缺点是不支持IE浏览器。
XAML是Microsoft即将推出的操作系统(Windows vista)的一个组件,XAML是可扩展应用标记语言(eXtensible Application Markup Language)的缩写。XAML结合Avalon图形引擎为Vista创建用户界面定义了标准,将来XAML很可能模糊桌面应用程序与Web应用程序之间的差别。XAML的缺点是只支持Windows操作系统。
Flex也是Macromedia公司开发的专业RIA解决方案,利用MXML(Maximum eXperience Markup Language)设计用户界面,并用ActionScript编写业务逻辑。其开发速度比纯Flash开发要快。Flex应用程序运行于Flex表示服务器之上,而Flex表示服务器可以建立在J2EE应用服务器或Servlet容器之上,也可以建立在.Net框架上。 Flex程序会在运行期间被Flex表示服务器编译成SWF格式的二进制文件,然后返回给客户端的Flash播放器展示给用户,Flex的缺点是由于增加了运行期编译环节导致速度较慢,而且相应的开发工具也比较昂贵,不过最近Macromedia公司将Flex 2免费发放了。
Laszlo是IBM开发的一个开源RIA开发环境,遵循OSI认证的CPL许可(Common Public License)。使用Laszlo开发RIA时,只需编写名为LZX的文件(其中整合了XML和JavaScript,类似XUL、MXML和XAML),运行在J2EE应用服务器上的Laszlo表示服务器会将其编译成SWF文件并传输到客户端的Flash播放器,这一点与Flex很相似。缺点和Flex一样,速度较慢。
所有RIA解决方案的一个共同缺点是运行速度相对较慢,所以要求用户有很高的网络带宽,否则速度将会难以忍受。由于Ajax是利用JavaScript和DOM等轻量级客户端技术,响应速度比RIA要快很多,故并不需要额外的网络带宽,同时也提供了丰富的用户体验。但单就提供用户体验来讲,以上RIA解决方案都比Ajax要丰富,所以一旦宽带网络普及, Ajax将会受到RIA解决方案的挤压。
三、 Ajax与Web 2.0
Web2.0是基于个性化微内容,提供注重用户体验,用户可以参与的社会化网络服务平台,包括Blog, RSS/ATOM数据聚合,Tag,SNS, Wiki, Podcast等应用。Web2.0的应用可以最大限度地发挥因特网平台的优势,将会随着越来越多的人使用而不停的更新、消费并混合个人用户产生的微内容,同时通过允许别人对其进行混合的方式提供给这些人个性化的服务,从而建立起一个全社会参与性的网络效应,并且超越Web1.0的方式提供更好的用户体验。Web2.0网站中每个用户不光是一个终端,还要变成一个节点,直接成为网络资源的一部分。
Web2.0的基础是可重用的微内容,但最终目的依然是提供更好的用户体验,使用户可以更方便地查看感兴趣的信息,更有效地组织信息,更快捷地生产信息。这些方面和Ajax的宗旨很吻合。事实上,包括Flickr,Gmail,365Kit在内的很多Web2.0网站都用到Ajax技术来提供更好的用户体验。Ajax能改进Web2.0网站的用户体验,同样,由于Web2.0的流行才导致了Ajax技术的发展。
采用Ajax技术的Web2.0应用,客户端的编码量一般比较大,为了保持代码的可读性,页面应该尽量采用XHTML编写。传统的HTML制作页面的方法会把数据和样式表混合在一起,很容易出错,而且也不利于以后的维护和修改。
四、 基于Ajax的Web开发示例
在此采用一个简单的购物车示例,在向里面添加项目时,它会动态更新。这项技术如果整合到在线商店,那么用户可以持续地浏览和向购物车中添加项目,而不必在每次点击之后都等待完整的页面刷新。清单 1 显示了购物车示例使用的有关 HTML代码。
清单1. 购物车示例的HTML代码和JavaScript代码
<!DOCTYPE HTML PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Using Ajax for cart</title>
<script type="text/javascript"> var lastCartUpdate = 0; var xmlHttp;
function createXMLHttpRequest() { // Create XMLHttpRequest object in non-Microsoft browsers if (window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest(); } else if (window.ActiveXObject) { try { // Try to create XMLHttpRequest in later versions of IE xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e1) { try { // Try version supported by older versions of IE xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e2) { alert("Can't create XMLHttpRequest object"); } } } }
function callback() { // If the request's status is "complete" if (xmlHttp.readyState == 4) { // Check that we received a successful response from the server if (xmlHttp.status == 200) { updateCart(xmlHttp.responseXML); } else { alert("HTTP error "+xmlHttp.status+": "+xmlHttp.statusText); } } }
function addToCart(itemCode) { createXMLHttpRequest(); xmlHttp.onreadystatechange = callback; xmlHttp.open("POST", "cart.do", true); xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xmlHttp.send("action=add&item="+itemCode); }
function updateCart(cartXML) { var cart = cartXML.getElementsByTagName("cart")[0]; var generated = cart.getAttribute("generated"); if (generated > lastCartUpdate) { lastCartUpdate = generated; var contents = document.getElementById("contents"); contents.innerHTML = ""; var items = cart.getElementsByTagName("item"); for (var i = 0 ; i < items.length ; i++) { var item = items[i]; var name = item.getElementsByTagName("name")[0].firstChild.nodeValue; var quantity = item.getElementsByTagName("quantity")[0].firstChild.nodeValue; var listItem = document.createElement("li"); listItem.appendChild(document.createTextNode(name+" x "+quantity)); contents.appendChild(listItem); } } document.getElementById("total").innerHTML = cart.getAttribute("total"); }
</script> </head> <body>
<table border="1"> <thead> <th>Name</th> <th>Description</th> <th>Price</th> <th></th> </thead> <tbody> <tr> <td>Hat</td> <td>Stylish bowler hat</td> <td>$19.99</td> <td> <button onclick="addToCart('hat001')">Add to Cart</button> </td> </tr> <tr> <td>Dog</td> <td>Chocolate labrador puppy</td> <td>$79.99</td> <td> <button onclick="addToCart('dog001')">Add to Cart</button> </td> </tr> <tr> <td>Soup</td> <td>Can of tasty tomato soup</td> <td>$1.99</td> <td> <button onclick="addToCart('sou001')">Add to Cart</button> </td> </tr> <tr> <td>Chair</td> <td>Swivelling office chair</td> <td>$49.99</td> <td> <button onclick="addToCart('cha001')">Add to Cart</button> </td> </tr> </tbody> </table> <ul id="cart-contents"> <!-- List-items will be added here for each item in the cart --> </ul> Total cost:<span id="total">$0.00</span> </body> </html>
|
处理Ajax请求的服务器端用Servlet实现,代码如下:
清单 2. 处理 Ajax 请求的 servlet 代码
public void doPost(HttpServletRequest req, HttpServletResponse res) throws java.io.IOException { Cart cart = getCartFromSession(req); String action = req.getParameter("action"); String item = req.getParameter("item");
if ((action != null) && (item != null)) { if ("add".equals(action)) { cart.addItem(item); } } //Serialize the Cart's state to XML String cartXml = cart.toXml(); //Write XML to response. res.setContentType("text/xml"); res.getWriter().write(cartXml); } |
清单 3 显示了 Cart.toXml()
方法生成的示例 XML。它很简单。请注意 cart
元素的 generated
属性,它是 System.currentTimeMillis()
生成的一个时间戳。
清单 3. Cart 对象的XML 序列化示例
<?xml version="1.0"?> <cart generated="1123969988414" total="$171.95"> <item code="hat001"> <name>Hat</name> <quantity>2</quantity> </item> <item code="cha001"> <name>Chair</name> <quantity>1</quantity> </item> <item code="dog001"> <name>Dog</name> <quantity>1</quantity> </item> </cart> |
为了便于读者看懂上面的代码,我解释一下XMLHttpRequest这个对象的方法和属性如下:
XMLHttpRequest 对象方法
方法 | 描述 |
abort() | 停止当前请求 |
getAllResponseHeaders() | 作为字符串返问完整的headers |
getResponseHeader("headerLabel") | 作为字符串返问单个的header标签 |
open("method","URL"[,asyncFlag[,"userName"[, "password"]]]) | 设置未决的请求的目标 URL, 方法, 和其他参数 |
send(content) | 发送请求 |
setRequestHeader("label", "value") | 设置header并和请求一起发送 |
XMLHttpRequest 对象属性
属性 | 描述 |
onreadystatechange | 状态改变的事件触发器 |
readyState | 对象状态(integer): |
responseText | 服务器进程返回数据的文本版本 |
responseXML | 服务器进程返回数据的兼容DOM的XML文档对象 |
status | 服务器返回的状态码, 如:404 = "文件末找到" 、200 ="成功" |
statusText | 服务器返回的状态文本信息 |
五、 主要Ajax框架介绍
通过上面的例子,读者应该清楚即使创建一个跨浏览器的XMLHTTPRequest对象都不是一项简单的工作(见清单 1),像这样的浏览器兼容性问题在Ajax中还有很多,同时考虑到简化开发工作的目的,这就催生了很多Ajax框架,下面介绍其中一些框架。
Dojo
授权协议: Academic Free License v 2.1
简介:
Dojo是最老的框架之一,于2004年9月开始开发。这个项目的目标是建立充分利用XMLHTTPRequest的DHTML工具包,并把重心放在可用性问题上。Dojo只有几个文件,不用处理XMLHTTPRequest的建立,只需调用bind方法,并传入想调用的URL和回调方法即可。大大简化了开发工作。 Dojo还有一个特性,它支持向后和向前按钮,但是这个特性不是在每个浏览器都能用(Safari不能用)。
Rico
授权协议: Apache 2.0
简介:
Rico由Sabre Airline Solutions开发,随后又成为开源实现。这个项目的目标是提供一组组件来开发丰富的因特网应用,得到了广泛的浏览器支持。与Dojo关注可用性不同,Rico是针对托放动作、电影效果而设计。
DWR(Direct Web Remoting)
网址:http://www.getahead.ltd.uk/dwr/
授权协议: Apache 2.0
简介:
利用DWR,可以在JavaScript代码中直接调用Java方法,就好像调用浏览器的本地方法一样;DWR和很多开源Java框架,如Spring、Struts、Hibernate、DOM4j能很好的集成起来;DWR的文档也很详细,还有一些有用的例子可以帮助开发者入门。不足的是DWR只支持Java语言。
Sajax
网址:http://www.modernmethod.com/sajax/
授权协议: BSD
简介:
与DWR类似,Sajax允许从JavaScript调用服务器端代码,支持Perl、Python、Ruby和ASP等语言,但却不支持Java和JSP。
除了以上介绍的框架之外,还有Microsoft的Atlas、Ruby on Rails的Prototype、qooxdoo、 Google的AJAXSLT、SACK、AjaxAnywhere等框架,而且新的框架也在不断涌现出来,可以预见不远的将来Ajax框架会面临一次优胜劣汰,留下来的框架将会是最优秀的。
六、 Ajax的优点
1、减轻服务器的负担。因为Ajax的根本理念是“按需取数据”,所以最大可能在减少了冗余请求和响影对服务器和网络带宽造成的负担,节约空间和带宽租用成本;
2、无刷新更新页面,减少用户实际和心理等待时间,即提供了更好的用户体验;
3、基于标准化的并被广泛支持和技术,并且不需要插件或下载小程序;
4、学习成本低,上手比较快。
七、 Ajax的缺点
1、一些手持设备现在还不能很好的支持Ajax;
2、客户端代码膨胀,而且显示和逻辑混合在一起,不利于维护和修改;
3、不支持“后退”操作,无法对页面建立书签,对搜索引擎支持不好;
4、用JavaScript作的Ajax引擎,对各种浏览器的兼容性不好,同时JavaScript的调试比较困难;
5、Ajax的无刷新重载,由于页面的变化没有刷新重载那么明显,所以容易给用户带来困扰——用户不太清楚现在的数据是旧的还是已经更新过的,现有的解决方案包括在相关位置提示、数据更新的区域设计得比较明显、数据更新后给用户提示等;
6、对多媒体的支持没有FLASH、Java Applet好。
1. 《Foundations of Ajax》;Ryan Asleson, Nathaniel T.Schutta; Apress,2005.10
2. 《Ajax in action》;Dave Crane,Eric Pascarello,Darren James;Manning,2005.11
3. IBM DeveloperWorks(www.ibm.com/developerworks/cn)
6. www.devx.com