掌握Ajax第2部分 使用JavaScript和Ajax发出异步请求.docx
《掌握Ajax第2部分 使用JavaScript和Ajax发出异步请求.docx》由会员分享,可在线阅读,更多相关《掌握Ajax第2部分 使用JavaScript和Ajax发出异步请求.docx(25页珍藏版)》请在冰点文库上搜索。
掌握Ajax第2部分使用JavaScript和Ajax发出异步请求
掌握Ajax,第2部分:
使用JavaScript和Ajax发出异步请求
在Web请求中使用XMLHttpRequest
级别:
中级
BrettMcLaughlin(brett@newI),作家,编辑,O'ReillyMediaInc.
2006年2月16日
多数Web应用程序都使用请求/响应模型从服务器上获得完整的HTML页面。
常常是点击一个按钮,等待服务器响应,再点击另一个按钮,然后再等待,这样一个反复的过程。
有了Ajax和XMLHttpRequest对象,就可以使用不必让用户等待服务器响应的请求/响应模型了。
本文中,BrettMcLaughlin介绍了如何创建能够适应不同浏览器的XMLHttpRequest实例,建立和发送请求,并响应服务器。
本系列的上一期文章(请参阅参考资料中的链接),我们介绍了Ajax应用程序,考察了推动Ajax应用程序的基本概念。
其中的核心是很多您可能已经了解的技术:
JavaScript、HTML和XHTML、一点动态HTML以及DOM(文档对象模型)。
本文将放大其中的一点,把目光放到具体的Ajax细节上。
本文中,您将开始接触最基本和基础性的有关Ajax的全部对象和编程方法:
XMLHttpRequest对象。
该对象实际上仅仅是一个跨越所有Ajax应用程序的公共线程,您可能已经预料到,只有彻底理解该对象才能充分发挥编程的潜力。
事实上,有时您会发现,要正确地使用XMLHttpRequest,显然不能使用XMLHttpRequest。
这到底是怎么回事呢?
Web2.0一瞥
在深入研究代码之前首先看看最近的观点——一定要十分清楚Web2.0这个概念。
听到Web2.0这个词的时候,应该首先问一问“Web1.0是什么?
”虽然很少听人提到Web1.0,实际上它指的就是具有完全不同的请求和响应模型的传统Web。
比如,到A网站上点击一个按钮或者输入搜索项。
就会对服务器发送一个请求,然后响应再返回到浏览器。
该请求不仅仅是图书和书目列表,而是另一个完整的HTML页面。
因此当Web浏览器用新的HTML页面重绘时,可能会看到闪烁或抖动。
事实上,通过看到的每个新页面可以清晰地看到请求和响应。
Web2.0(在很大程度上)消除了这种看得见的往复交互。
比如访问GoogleMaps或Flickr这样的站点(到这些支持Web2.0和Ajax站点的链接请参阅参考资料)。
比如在GoogleMaps上,您可以拖动地图,放大和缩小,只有很少的重绘操作。
当然这里仍然有请求和响应,只不过都藏到了幕后。
作为用户,体验更加舒适,感觉很像桌面应用程序。
这种新的感受和范型就是当有人提到Web2.0时您所体会到的。
需要关心的是如何使这些新的交互成为可能。
显然,仍然需要发出请求和接收响应,但正是针对每次请求/响应交互的HTML重绘造成了缓慢、笨拙的Web交互的感受。
因此很清楚,我们需要一种方法使发送的请求和接收的响应只包含需要的数据而不是整个HTML页面。
惟一需要获得整个新HTML页面的时候就是希望用户看到新页面的时候。
但多数交互都是在已有页面上增加细节、修改主体文本或者覆盖原有数据。
这些情况下,Ajax和Web2.0方法允许在不更新整个HTML页面的情况下发送和接收数据。
对于那些经常上网的人,这种能力可以让您的应用程序感觉更快、响应更及时,让他们不时地光顾您的网站。
XMLHttpRequest简介
要真正实现这种绚丽的奇迹,必须非常熟悉一个JavaScript对象,即XMLHttpRequest。
这个小小的对象实际上已经在几种浏览器中存在一段时间了,它是本专栏今后几个月中要介绍的Web2.0、Ajax和大部分其他内容的核心。
为了让您快速地大体了解它,下面给出将要用于该对象的很少的几个方法和属性。
∙open():
建立到服务器的新请求。
∙send():
向服务器发送请求。
∙abort():
退出当前请求。
∙readyState:
提供当前HTML的就绪状态。
∙responseText:
服务器返回的请求响应文本。
如果不了解这些(或者其中的任何一个),您也不用担心,后面几篇文章中我们将介绍每个方法和属性。
现在应该了解的是,明确用XMLHttpRequest做什么。
要注意这些方法和属性都与发送请求及处理响应有关。
事实上,如果看到XMLHttpRequest的所有方法和属性,就会发现它们都与非常简单的请求/响应模型有关。
显然,我们不会遇到特别新的GUI对象或者创建用户交互的某种超极神秘的方法,我们将使用非常简单的请求和非常简单的响应。
听起来似乎没有多少吸引力,但是用好该对象可以彻底改变您的应用程序。
简单的new
首先需要创建一个新变量并赋给它一个XMLHttpRequest对象实例。
这在JavaScript中很简单,只要对该对象名使用new关键字即可,如清单1所示。
清单1.创建新的XMLHttpRequest对象
varrequest=newXMLHttpRequest();
不难吧?
记住,JavaScript不要求指定变量类型,因此不需要像清单2那样做(在Java语言中可能需要这样)。
清单2.创建XMLHttpRequest的Java伪代码
XMLHttpRequestrequest=newXMLHttpRequest();
因此在JavaScript中用var创建一个变量,给它一个名字(如“request”),然后赋给它一个新的XMLHttpRequest实例。
此后就可以在函数中使用该对象了。
错误处理
在实际上各种事情都可能出错,而上面的代码没有提供任何错误处理。
较好的办法是创建该对象,并在出现问题时优雅地退出。
比如,任何较早的浏览器(不论您是否相信,仍然有人在使用老版本的NetscapeNavigator)都不支持XMLHttpRequest,您需要让这些用户知道有些地方出了问题。
清单3说明如何创建该对象,以便在出现问题的时候发出JavaScript警告。
清单3.创建具有错误处理能力的XMLHttpRequest
varrequest=false;
try{
request=newXMLHttpRequest();
}catch(failed){
request=false;
}
if(!
request)
alert("ErrorinitializingXMLHttpRequest!
");
一定要理解这些步骤:
1.创建一个新变量request并赋值false。
后面将使用false作为判定条件,它表示还没有创建XMLHttpRequest对象。
2.增加try/catch块:
1.尝试创建XMLHttpRequest对象。
2.如果失败(catch(failed))则保证request的值仍然为false。
3.检查request是否仍为false(如果一切正常就不会是false)。
4.如果出现问题(request是false)则使用JavaScript警告通知用户出现了问题。
代码非常简单,对大多数JavaScript和Web开发人员来说,真正理解它要比读写代码花更长的时间。
现在已经得到了一段带有错误检查的XMLHttpRequest对象创建代码,还可以告诉您哪儿出了问题。
应付Microsoft
看起来似乎一切良好,至少在用InternetExplorer试验这些代码之前是这样的。
如果这样试验的话,就会看到图1所示的糟糕情形。
图1.InternetExplorer报告错误
显然有什么地方不对劲,而InternetExplorer很难说是一种过时的浏览器,因为全世界有70%在使用InternetExplorer。
换句话说,如果不支持Microsoft和InternetExplorer就不会受到Web世界的欢迎!
因此我们需要采用不同的方法处理Microsoft浏览器。
经验证发现Microsoft支持Ajax,但是其XMLHttpRequest版本有不同的称呼。
事实上,它将其称为几种不同的东西。
如果使用较新版本的InternetExplorer,则需要使用对象Msxml2.XMLHTTP,而较老版本的InternetExplorer则使用Microsoft.XMLHTTP。
我们需要支持这两种对象类型(同时还要支持非Microsoft浏览器)。
请看看清单4,它在前述代码的基础上增加了对Microsoft的支持。
Microsoft参与了吗?
关于Ajax和Microsoft对该领域不断增长的兴趣和参与已经有很多文章进行了介绍。
事实上,据说Microsoft最新版本的InternetExplorer——version7.0,将在2006年下半年推出——将开始直接支持XMLHttpRequest,让您使用new关键字代替所有的Msxml2.XMLHTTP创建代码。
但不要太激动,仍然需要支持旧的浏览器,因此跨浏览器代码不会很快消失。
清单4.增加对Microsoft浏览器的支持
varrequest=false;
try{
request=newXMLHttpRequest();
}catch(trymicrosoft){
try{
request=newActiveXObject("Msxml2.XMLHTTP");
}catch(othermicrosoft){
try{
request=newActiveXObject("Microsoft.XMLHTTP");
}catch(failed){
request=false;
}
}
}
if(!
request)
alert("ErrorinitializingXMLHttpRequest!
");
很容易被这些花括号迷住了眼睛,因此下面分别介绍每一步:
1.创建一个新变量request并赋值false。
使用false作为判断条件,它表示还没有创建XMLHttpRequest对象。
2.增加try/catch块:
1.尝试创建XMLHttpRequest对象。
2.如果失败(catch(trymicrosoft)):
1.尝试使用较新版本的Microsoft浏览器创建Microsoft兼容的对象(Msxml2.XMLHTTP)。
2.如果失败(catch(othermicrosoft))尝试使用较老版本的Microsoft浏览器创建Microsoft兼容的对象(Microsoft.XMLHTTP)。
3.如果失败(catch(failed))则保证request的值仍然为false。
3.检查request是否仍然为false(如果一切顺利就不会是false)。
4.如果出现问题(request是false)则使用JavaScript警告通知用户出现了问题。
这样修改代码之后再使用InternetExplorer试验,就应该看到已经创建的表单(没有错误消息)。
我实验的结果如图2所示。
图2.InternetExplorer正常工作
静态与动态
再看一看清单1、3和4,注意,所有这些代码都直接嵌套在script标记中。
像这种不放到方法或函数体中的JavaScript代码称为静态JavaScript。
就是说代码是在页面显示给用户之前的某个时候运行。
(虽然根据规范不能完全精确地知道这些代码何时运行对浏览器有什么影响,但是可以保证这些代码在用户能够与页面交互之前运行。
)这也是多数Ajax程序员创建XMLHttpRequest对象的一般方式。
就是说,也可以像清单5那样将这些代码放在一个方法中。
清单5.将XMLHttpRequest创建代码移动到方法中
varrequest;
functioncreateRequest(){
try{
request=newXMLHttpRequest();
}catch(trymicrosoft){
try{
request=newActiveXObject("Msxml2.XMLHTTP");
}catch(othermicrosoft){
try{
request=newActiveXObject("Microsoft.XMLHTTP");
}catch(failed){
request=false;
}
}
}
if(!
request)
alert("ErrorinitializingXMLHttpRequest!
");
}
如果按照这种方式编写代码,那么在处理Ajax之前需要调用该方法。
因此还需要清单6这样的代码。
清单6.使用XMLHttpRequest的创建方法
varrequest;
functioncreateRequest(){
try{
request=newXMLHttpRequest();
}catch(trymicrosoft){
try{
request=newActiveXObject("Msxml2.XMLHTTP");
}catch(othermicrosoft){
try{
request=newActiveXObject("Microsoft.XMLHTTP");
}catch(failed){
request=false;
}
}
}
if(!
request)
alert("ErrorinitializingXMLHttpRequest!
");
}
functiongetCustomerInfo(){
createRequest();
//Dosomethingwiththerequestvariable
}
此代码惟一的问题是推迟了错误通知,这也是多数Ajax程序员不采用这一方法的原因。
假设一个复杂的表单有10或15个字段、选择框等,当用户在第14个字段(按照表单顺序从上到下)输入文本时要激活某些Ajax代码。
这时候运行getCustomerInfo()尝试创建一个XMLHttpRequest对象,但(对于本例来说)失败了。
然后向用户显示一条警告,明确地告诉他们不能使用该应用程序。
但用户已经花费了很多时间在表单中输入数据!
这是非常令人讨厌的,而讨厌显然不会吸引用户再次访问您的网站。
如果使用静态JavaScript,用户在点击页面的时候很快就会看到错误信息。
这样也很烦人,是不是?
可能令用户错误地认为您的Web应用程序不能在他的浏览器上运行。
不过,当然要比他们花费了10分钟输入信息之后再显示同样的错误要好。
因此,我建议编写静态的代码,让用户尽可能早地发现问题。
用XMLHttpRequest发送请求
得到请求对象之后就可以进入请求/响应循环了。
记住,XMLHttpRequest惟一的目的是让您发送请求和接收响应。
其他一切都是JavaScript、CSS或页面中其他代码的工作:
改变用户界面、切换图像、解释服务器返回的数据。
准备好XMLHttpRequest之后,就可以向服务器发送请求了。
欢迎使用沙箱
Ajax采用一种沙箱安全模型。
因此,Ajax代码(具体来说就是XMLHttpRequest对象)只能对所在的同一个域发送请求。
以后的文章中将进一步介绍安全和Ajax,现在只要知道在本地机器上运行的代码只能对本地机器上的服务器端脚本发送请求。
如果让Ajax代码在上运行,则必须中运行的脚本发送请求。
设置服务器URL
首先要确定连接的服务器的URL。
这并不是Ajax的特殊要求,但仍然是建立连接所必需的,显然现在您应该知道如何构造URL了。
多数应用程序中都会结合一些静态数据和用户处理的表单中的数据来构造该URL。
比如,清单7中的JavaScript代码获取电话号码字段的值并用其构造URL。
清单7.建立请求URL
varrequest=false;
try{
request=newXMLHttpRequest();
}catch(trymicrosoft){
try{
request=newActiveXObject("Msxml2.XMLHTTP");
}catch(othermicrosoft){
try{
request=newActiveXObject("Microsoft.XMLHTTP");
}catch(failed){
request=false;
}
}
}
if(!
request)
alert("ErrorinitializingXMLHttpRequest!
");
functiongetCustomerInfo(){
varphone=document.getElementById("phone").value;
varurl="/cgi-local/lookupCustomer.php?
phone="+escape(phone);
}
这里没有难懂的地方。
首先,代码创建了一个新变量phone,并把ID为“phone”的表单字段的值赋给它。
清单8展示了这个表单的XHTML,其中可以看到phone字段及其id属性。
清单8.BreakNeckPizza表单
Enteryourphonenumber:
onChange="getCustomerInfo();"/>
Yourorderwillbedeliveredto: