用AJAX开发智能Web应用程序之基础篇

简介:
一. 什么是AJAX?

  这个名字代表了异步javascript+ XMLHTTPRequest,并且意味着你可以在基于浏览器的javascript和服务器之间建立套接字通讯。其实AJAX并不是一种新技术,而是已 经成功地用于现代浏览器中的若干成功技术的可能性组合。所有的AJAX应用程序实现了一种“丰富的”UI——这是通过javascript操作HTML文 档对象模型并且经由XMLHttpRequest实现的精确定位的数据检索来实现的。典型的示例AJAX应用程序是Google Labs([url]http://labs.google.com[/url])的Google Maps和Google Suggest。这些应用程序现场监视用户输入并且提供实时的页面更新。最重要的是,在用户通过地图导航或输入一个查找字符串的同时,这些事件不需要刷新 页面。

  事实上,支持这些令人感到惊讶的应用的技术已经出现一段时间了,尽管它们要求复杂的技能以及使用浏览器的技巧。一些专利产品就 提供了相似的能力——如Macromedia Flash插件,Java Applets或.NET运行时——在达到实用上已经有一段时间了。把一种可与服务器通话的脚本组件引入到浏览器中的思想早在IE 5.0中就已经存在。Firefox和其它流行的浏览器也加入到浏览器大军中并以一种内置对象形式支持XMLHTTPRequest。随着跨平台浏览器的 出现,这些技术得到了认可并在2004年3月一家称为Adaptive Path的公司中正式提出了AJAX。

  简而言之,由于来自于Google的支持和安装了一点可用的浏览器技术,加上为了一种"更好的用户体验",每个人都在把客户端技术添加到Web应用程序上。

   二. AJAX与传统应用程序的区别

   一个传统Web应用程序模型实际上是一种基本的事件——用户被迫提交表单以实现页面交换。也就是说,表单提交和页面传送无法得到保证:还有更坏的情形 ——用户需要再次点击。这与AJAX截然不同-——数据跨过线路而不是完整的HTML页面传输。这种数据交换是经由特定的浏览器对象: XMLHttpRequest实现的;再由适当的逻辑来处理每个数据请求的结果,页面的特定区域而不是完整的页面被更新。结果是更快的速度,更少的拥挤和 更好的信息传送控制。

  传统型"click-refresh"Web应用程序强迫用户中断工作过程而等待页面的重装。通过引入AJAX技术,一个客户端脚本能够异步地与服务器通话,而用户仍能保持输入数据。除了对用户透明之外,这样的异步意味着服务器可以有更多时间来处理请求。

   传统Web应用程序把所有的处理代理到服务器并且强迫服务器进行状态管理。AJAX允许灵活划分应用程序逻辑以及客户和服务器之间的状态管理。这就消除 了一种"click-refresh"依赖性并且提供更好的服务器可伸缩性。当该状态存储在客户端,你就不必跨越服务器来维持会话或保存/结束状态-其使 用期限是由客户端来定义的。

   三. AJAX——分布式的MVC

  尽管AJAX应用程序依靠 javascript来实现描述层,然而处理能力和知识库仍然存在于服务器上。此时,AJAX应用程序大量的与J2EE服务器通讯——把数据输入/输出 Web服务和servlets。具有基于AJAX的描述层的J2EE应用程序和标准J2EE应用程序之间的区别首先在于,MVC是通过线路分布的。通过使 用AJAX,视图是本地的,而模型和控制器是分布式的——这使得开发者能够灵活地决定哪些部件会是基于客户端的。具体地说,本地视图通过巧妙地操作 HTML DOM而生成图形;控制器局部地处理用户输入并且根据开发者的判断扩展到服务器的处理——经由HTTP请求(Web服务,XML/RPC或其它)实现;模 型的远程部分是根据客户端需要而下载的以达到实时更新客户端页面;并且状态是在客户端收集的。

  在以后的AJAX文章中,我们将比较深入地讨论这里的每一种组件并提供有关它们联合在一起进行应用的示例。现在,先不多说,让我们详细地分析一个简单的AJAX示例。

   四. 邮政区号校验和查询

   我们将创建一个包含三个INPUT字段(Zip,City和State)的HTML页面。我们将保证,只要用户输入邮政区号的前三个数字,该页面上的字 段就会用第一个匹配的状态值填充。一旦用户输入了所有五位邮政区号数,我们将立即决定和填充相应的城市。如果邮政区号无效(在服务器的数据库没有找到), 那么我们将把邮政区号的边界设置为红色。这样的可视化线索有助于用户并且在现代浏览器中已经成为一种标准(作为一实例,当Firefox找到一个HTML 页面中的匹配关键字时,它会高亮与你在浏览器查找域输入的内容一致的部分)。

  让我们首先创建一个简单的包含三个INPUT字段的 HTML:zip,city和state。请注意,一旦一个字符输入进邮政区号字段域中,即调用方法zipChanged()。javascript函数 zipChanged()(见下)在当zip长度为3时调用函数updateState(),而在当zip长度为5时调用函数up-dateCity ()。而updateCity()和updateState()把大部分的工作代理到另一个函数ask()。

Zip:<input id="zipcode" type="text" maxlength="5" onKeyUp="zipChanged()"
style="width:60"/>
City: <input id="city" disabled maxlength="32" style="width:160"/>
State:<input id="state" disabled maxlength="2" style="width:30"/>
<script src="xmlhttp.js"></script>
<script>
var zipField = null;
function zipChanged(){
zipField = document.getElementById("zipcode")
var zip = zipField.value;
zip.length == 3?updateState(zip):zip.length == 5?updateCity(zip):"";
}
function updateState(zip) {
var stateField = document.getElementById("state");
ask("resolveZip.jsp?lookupType=state&zip="+zip, stateField, zipField);
}
function updateCity(zip) {
var cityField = document.getElementById("city");
ask("resolveZip.jsp? lookupType=city&zip="+zip, cityField, zipField);
}
</script>

   函数ask()与服务器进行通讯并分配一个回调函数来处理服务器的响应(见下列代码)。后面,我们将分析具有双重特点的resolveZip.jsp的 内容-它根据zip字段中的字符数查找city或state信息。重要的是,ask()使用了具有异步特点的XmlHttpRequest,这样填充 state和city字段或着色zip字段边界就可以不必减慢数据入口而得以实现。首先,我们调用request.open()-它用服务器打开套接字频 道,使用一个HTTP动词(GET或POST)作为第一个参数并且以数据提供者的URL作为第二个参数。request.open()的最后一个参数被设 置为true-它指示该请求的异步特性。注意,该请求还没有被提交。随着对request.send()的调用,开始提交-这可以为POST提供任何必要 的有效载荷。在使用异步请求时,我们必须使用request.onreadystatechanged属性来分配请求的回调函数。(如果请求是同步的话, 我们应该能够在调用request.send之后立即处理结果,但是我们也有可能阻断用户,直到该请求完成为止。)

HTTPRequest = function () {
var xmlhttp=null;
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (_e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (_E) { }
}
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
try {
xmlhttp = new XMLHttpRequest();
} catch (e) {
xmlhttp = false;
}
}
return xmlhttp;
}

function ask(url, fieldToFill, lookupField) {
var http = new HTTPRequest();
http.open("GET", url, true);
http.onreadystatechange = function (){ handleHttpResponse(http, fieldToFill,lookupField)};
http.send(null);
}

function handleHttpResponse(http, fieldToFill, lookupField) {
if (http.readyState == 4) {
result = http.responseText;
if ( -1 != result.search("null") ) {
lookupField.style.borderColor = "red";
fieldToFill.value = "";
} else {
lookupField.style.borderColor = "";
fieldToFill.value = result;
}
}
}

  为ask()所使用的HttpRequest()函数(见上)是一跨浏览器的XMLHTTPRequest的一个实例的构造器;稍后我 们将分析它。到目前为止,请注意对于handleResponse()的调用是如何用一匿名函数包装的-这个函数是function() {handleHttpResponse(http,fieldToFill, lookupField)}。

  该函数的代码是动态创 建的并且在每次我们给http.onreadstatechange属性赋值时被编译。结果,javascript创建一个指向上下文(所有的变量都可以 存取正在结束的方法-ask())的指针。这样以来,匿名函数和handleResponse()就能够被保证充分存取所有的上下文宿主的变量,直至到匿 名函数的参考被垃圾回收站收集为止。换句话说,无论何时我们的匿名函数被调用,它都能无缝地参考request,fieldToFill和 lookupField变量,就象它们是全局的一样。而且,每次ask()调用都将创建环境的一个独立拷贝,并且此时这些变量中保存有该函数将结束时的 值。

  现在,让我们分析一下函数handleResponse()。既然它能够在请求处理的不同状态下激活,那么该函数将忽略所有的情 形-除了该请求处理完成之外-这相应于request.readyState属性等于4("Completed")。此时,该函数读取服务器的响应文本。 与它的名字所暗示的相反,XmlHttpRequest的输入和输出都不必限于XML格式。特别地,我们的resolveZip.jsp(见源码中的列表 1)返回普通文本。如果返回值为"unknown",那么该函数将假定邮政区号是无效的并且把查找字段(zip)边界颜色置为红色。否则,返回值被用于填 充字段state或city,并且zip的边界被赋予一种缺省颜色。

  XMLHttpRequest-传输对象

  让 我们返回到我们的XMLHTTPRequest的跨浏览器实现。最后一个列表包含一个HttpRequest()函数-它向上兼容于IE5.0和 Mozilla 1.8/FireFox。为简化起见,我们只创建一个微软XMLHTTPRequest对象,而且如果创建失败,我们假定它是 Firefox/Mozilla。

  该函数的核心是XMLHTTPRequest-这是一个本机浏览器对象,它为包括HTTP协议的任 何东西与服务器之间的通讯提供方便。它允许指定任何HTTP动词,头部和有效载荷,并且能够以异步或同步方式工作。不需要下载也不需要安装任何插件-尽管 在IE的情形下,XMLHTTPRequest是一个集成到浏览器内部的ActiveX。因而,"Run ActiveX Control and Plugins"默认IE权限应该正好适合使用它。

  最重要的是,XMLHTTPRequest允许一个到服务器的RPC风格的编程查 询而不需要任何页面刷新。它以一种可预测的,可控制的方式来实现此-提供了到HTTP协议的所有细节的完整存取-包括头部和数据的任何定制格式。在以后的 文章中,我们将向你展示其它一些业界协议-你可以在这些传输协议(如Web服务和XML-RPC)之上运行-它们极大地简化大规模应用程序的开发和维护。
五.服务器端逻辑

  最后,服务器端的resolveZip.jsp被从函数ask()中调用(见所 附源码中的列表1)。这个resolveZip.jsp在两种由当前的邮政区号长度所区分的独立的场所下被调用(见zipChanged()函数)。请求 参数lookupType的值或者是state或者是city。为简化起见,我们将假定,两个文件state.properties和 city.properties都位于服务器中C驱动器的根目录下。resolveZip.jsp逻辑负责用适当的预装载的文件返回查找值。
我们的支持AJAX的页面现在已经准备好了。

   六.远程脚本技术-一种可选方法

   一些更旧的AJAX实现是基于所谓的远程脚本技术。这种思想是,用户的行为导致经由IFRAME对服务器进行查询,而服务器用javascript作出 响应,该脚本一旦到达客户端立即被执行。这与XMLHttpRequest方法相比存在较大的区别,在后者情况下,服务器响应数据而客户端解释数据。其好 处是这种解决方案支持更旧的浏览器。 

  基于IFRAME示例的HTML部分(见所附源码中的列表2)与我们在XMLHTTPRequest场合下所用的极相似,但是这次我们将引入另外一个IFRAME元素-controller:

Zip:<input id="zipcode" type="text" maxlength="5" onKeyUp="zipChanged()"
style="width:60" size="20"/>
City: <input id="city" disabled maxlength="32" style="width:160" size="20"/>
State:<input id="state" disabled maxlength="2" style="width:30" size="20"/>
<iframe id="controller" style="visibility:hidden;width:0;height:0"></iframe>

  我们保持每次击键都调用zipChanged()一次,但是这一次,从zipChanged()中被调用的函数ask()(见所附源码中的列表3)负责设置IFRAME的src属性,而不是调用一个XMLHTTPRequest:

function ask(url, fieldToFill, lookupField){
var controller = document.getElementById("controller");
controller.src= url+"&field="+fieldToFill.id+"&zip="+lookupField.id;
}

   服务器端逻辑由一个粗略的resolveZip.jsp(见所附源码中的列表4)所描述。它与它的XMLHTTPRequest对应物相区别-它返回 javascript语句,这些语句设置变量字段lookup和city的全局值,而且一旦它到达浏览器即从全局窗口的执行上下文中调用函数 response()。

  函数response()是一修改版本的handleResponse()-这一函数可以免于处理未完成的请求(详见本文所附源码中的列表2)。

   七. 难题

  为简化起见,让我们"俯看"一下在我们的示例代码中的一些重要的问题:

  1.事实-XMLHTTPRequest对象实例和回调函数调用在被使用以后并没被破坏-在每次调用后这有可能导致内存泄漏。适当编写的代码应该破坏或重用对象池中的这些实例。而且,客户端必须使用与服务器软件相同的对象管理技术。

   2.在大多数情况下,错误往往得不到有效处理。例如,在方法ask()中对request.open()的调用可能引发一个异常,这是必须要捕获和处理 的,即使在浏览器中没有设置javascript异常自动捕获功能。而handleResponse()函数又是另外一个例子。它必须要为可能的服务器端 和通讯错误而检查headers和responseText值。在发生错误的情况下,它必须尽力恢复并/或者报告错误。正确开发的AJAX应用程序要尽可 能避免"提交"松散的数据,因为往往存在线路断开和其它低级通讯的问题-所以这些程序必须建立一个强壮的和自恢复的框架为此提供支持。

   3.当前服务器端框架提供相当多的功能-它们可以与一种自由刷新方法和谐相处。例如,让我们考虑一个定制的在指定时间内的服务器端认证的问题。在这种情 况下,我们必须拦截到XMLHTTPRequest调用的安全系统响应,显示登录屏幕,然后在用户被认证后重新发出请求。

  所有的这些问题只是一些典型的用低级API工作的任何应用程序代码,而且所有这些问题都能被解决。好消息是,解决这些问题所需要的技术十分相似于大多数Java开发技术,如Web服务,定制标签和XML/XSLT。唯一的区别在于,现在这些技术以下列形式用于客户端:

  ·Web服务-使用SOAP/REST/RPC等简单通讯标准

  ·客户端定制标签-打包丰富的客户端控件并集成AJAX功能

  ·数据操作-基于XML和基于XSLT技术

   八. 小结

   AJAX方法能够向人们提供一种与桌面应用程序相同的丰富的互联网体验。但是,我们必须有选择地使用AJAX技术,如当你仍在线购物时,你绝对不想让你 的信用卡通过后台处理就悄悄地开始付款。AJAX会成为一种持续的动力吗?我们当然希望这样。在过去的五年时间内我们一直在努力开发AJAX应用程序并且 能证明它是健全并且很有效的。然而,它要求一个开发者必须精通大量技术而不是在传统的"click-refresh"Web应用程序中所使用的那些。














本文转自朱先忠老师51CTO博客,原文链接: http://blog.51cto.com/zhuxianzhong/59879,如需转载请自行联系原作者



相关文章
|
15天前
|
监控 JavaScript 前端开发
《理解 WebSocket:Java Web 开发的实时通信技术》
【4月更文挑战第4天】WebSocket是Java Web实时通信的关键技术,提供双向持久连接,实现低延迟、高效率的实时交互。适用于聊天应用、在线游戏、数据监控和即时通知。开发涉及服务器端实现、客户端连接及数据协议定义,注意安全、错误处理、性能和兼容性。随着实时应用需求增加,WebSocket在Java Web开发中的地位将更加重要。
|
1天前
|
JSON Java fastjson
Spring Boot 底层级探索系列 04 - Web 开发(2)
Spring Boot 底层级探索系列 04 - Web 开发(2)
11 0
|
1天前
|
安全 编译器 PHP
PHP 8.1版本发布:引领Web开发新潮流
PHP编程语言一直是Web开发的主力军,而最新发布的PHP 8.1版本则为开发者们带来了更多创新和便利。本文将介绍PHP 8.1版本的主要特性,包括更快的性能、新的语言功能和增强的安全性,以及如何利用这些功能来提升Web应用程序的质量和效率。
|
1天前
|
SQL 安全 Go
如何在 Python 中进行 Web 应用程序的安全性管理,例如防止 SQL 注入?
在Python Web开发中,确保应用安全至关重要,主要防范SQL注入、XSS和CSRF攻击。措施包括:使用参数化查询或ORM防止SQL注入;过滤与转义用户输入抵御XSS;添加CSRF令牌抵挡CSRF;启用HTTPS保障数据传输安全;实现强身份验证和授权系统;智能处理错误信息;定期更新及审计以修复漏洞;严格输入验证;并培训开发者提升安全意识。持续关注和改进是保证安全的关键。
9 0
|
4天前
|
PHP
web简易开发——通过php与HTML+css+mysql实现用户的登录,注册
web简易开发——通过php与HTML+css+mysql实现用户的登录,注册
|
4天前
|
前端开发 数据挖掘 API
使用Python中的Flask框架进行Web应用开发
【4月更文挑战第15天】在Python的Web开发领域,Flask是一个备受欢迎的轻量级Web框架。它简洁、灵活且易于扩展,使得开发者能够快速地构建出高质量的Web应用。本文将深入探讨Flask框架的核心特性、使用方法以及在实际开发中的应用。
|
13天前
|
安全 前端开发 Java
Java Web开发知识点学习总结
Java Web开发涉及Java基础、Servlet、JSP、数据库操作(SQL+JDBC)、MVC设计模式、Spring框架、Hibernate ORM、Web服务(SOAP&RESTful)、安全认证(HTTP Basic/Digest/OAuth)及性能优化(缓存、异步、负载均衡)。
15 3
|
16天前
|
XML JSON JavaScript
使用JSON和XML:数据交换格式在Java Web开发中的应用
【4月更文挑战第3天】本文比较了JSON和XML在Java Web开发中的应用。JSON是一种轻量级、易读的数据交换格式,适合快速解析和节省空间,常用于API和Web服务。XML则提供更强的灵活性和数据描述能力,适合复杂数据结构。Java有Jackson和Gson等库处理JSON,JAXB和DOM/SAX处理XML。选择格式需根据应用场景和需求。
|
Web App开发 JavaScript 前端开发
用jabsorb(json) for java编写AJAX应用程序
用jabsorb(json) for java编写AJAX应用程序 本文为原创,如需转载,请注明作者和出处,谢谢!jabsorb是一种基于Ajax/Web 2.0的简单轻便的框架,可用于在Web浏览中通过HTTP请求向服务端发送请求,并获得响应数据。
913 0