掌握 Ajax 第 3 部分Ajax 中的高级请求和响应.docx
- 文档编号:23714928
- 上传时间:2023-05-20
- 格式:DOCX
- 页数:20
- 大小:180.80KB
掌握 Ajax 第 3 部分Ajax 中的高级请求和响应.docx
《掌握 Ajax 第 3 部分Ajax 中的高级请求和响应.docx》由会员分享,可在线阅读,更多相关《掌握 Ajax 第 3 部分Ajax 中的高级请求和响应.docx(20页珍藏版)》请在冰豆网上搜索。
掌握Ajax第3部分Ajax中的高级请求和响应
掌握Ajax,第3部分:
Ajax中的高级请求和响应
全面理解HTTP的状态代码、就绪状态和XMLHttpRequest对象
级别:
初级
BrettMcLaughlin,作家,编辑,O'ReillyMediaInc.
2006年3月23日
对于很多Web开发人员来说,只需要生成简单的请求并接收简单的响应即可;但是对于希望掌握Ajax的开发人员来说,必须要全面理解HTTP状态代码、就绪状态和XMLHttpRequest对象。
在本文中,BrettMcLaughlin将向您介绍各种状态代码,并展示浏览器如何对其进行处理,本文还给出了在Ajax中使用的比较少见的HTTP请求。
在本系列的上篇文章中,我们将详细介绍XMLHttpRequest对象,它是Ajax应用程序的中心,负责处理服务器端应用程序和脚本的请求,并处理从服务器端组件返回的数据。
由于所有的Ajax应用程序都要使用XMLHttpRequest对象,因此您可能会希望熟悉这个对象,从而能够让Ajax执行得更好。
在本文中,我将在上一篇文章的基础上重点介绍这个请求对象的3个关键部分的内容:
∙HTTP就绪状态
∙HTTP状态代码
∙可以生成的请求类型
这三部分内容都是在构造一个请求时所要考虑的因素;但是介绍这些主题的内容太少了。
然而,如果您不仅仅是想了解Ajax编程的常识,而是希望了解更多内容,就需要熟悉就绪状态、状态代码和请求本身的内容。
当应用程序出现问题时——这种问题总是存在——那么如果能够正确理解就绪状态、如何生成一个HEAD请求或者400的状态代码的确切含义,就可以在5分钟内调试出问题,而不是在各种挫折和困惑中度过5个小时。
XMLHttpRequest或XMLHttp:
换名玫瑰
Microsoft™和InternetExplorer使用了一个名为XMLHttp的对象,而不是XMLHttpRequest对象,而Mozilla、Opera、Safari和大部分非Microsoft浏览器都使用的是后者。
为了简单性起见,我将这两个对象都简单地称为XMLHttpRequest。
这既符合我们在Web上看到的情况,又符合Microsoft在InternetExplorer7.0中使用XMLHttpRequest作为请求对象的意图。
(有关这个问题的更多内容,请参见第2部分。
)
下面让我们首先来看一下HTTP就绪状态。
深入了解HTTP就绪状态
您应该还记得在上一篇文章中XMLHttpRequest对象有一个名为readyState的属性。
这个属性确保服务器已经完成了一个请求,通常会使用一个回调函数从服务器中读出数据来更新Web表单或页面的内容。
清单1给出了一个简单的例子(这也是本系列的上一篇文章中的一个例子——请参见参考资料)。
清单1.在回调函数中处理服务器的响应
functionupdatePage(){
if(request.readyState==4){
if(request.status==200){
varresponse=request.responseText.split("|");
document.getElementById("order").value=response[0];
document.getElementById("address").innerHTML=
response[1].replace(/\n/g,"
");
}else
alert("statusis"+request.status);
}
}
这显然是就绪状态最常见(也是最简单)的用法。
正如您从数字"4"中可以看出的一样,还有其他几个就绪状态(您在上一篇文章中也看到过这个清单——请参见参考资料):
∙0:
请求未初始化(还没有调用open())。
∙1:
请求已经建立,但是还没有发送(还没有调用send())。
∙2:
请求已发送,正在处理中(通常现在可以从响应中获取内容头)。
∙3:
请求在处理中;通常响应中已有部分数据可用了,但是服务器还没有完成响应的生成。
∙4:
响应已完成;您可以获取并使用服务器的响应了。
如果您希望不仅仅是了解Ajax编程的基本知识,那么就不但需要知道这些状态,了解这些状态是何时出现的,以及如何来使用这些状态。
首先,您需要学习在每种就绪状态下可能碰到的是哪种请求状态。
不幸的是,这一点并不直观,而且会涉及几种特殊的情况。
隐秘就绪状态
第一种就绪状态的特点是readyState属性为0(readyState==0),表示未初始化状态。
一旦对请求对象调用open()之后,这个属性就被设置为1。
由于您通常都是在一对请求进行初始化之后就立即调用open(),因此很少会看到readyState==0的状态。
另外,未初始化的就绪状态在实际的应用程序中是没有真正的用处的。
不过为了满足我们的兴趣,请参见清单2的内容,其中显示了如何在readyState被设置为0时来获取这种就绪状态。
清单2.获取0就绪状态
functiongetSalesData(){
//Createarequestobject
createRequest();
alert("Readystateis:
"+request.readyState);
//Setup(initialize)therequest
varurl="/boards/servlet/UpdateBoardSales";
request.open("GET",url,true);
request.onreadystatechange=updatePage;
request.send(null);
}
在这个简单的例子中,getSalesData()是Web页面调用来启动请求(例如点击一个按钮时)所使用的函数。
注意您必须在调用open()之前来查看就绪状态。
图1给出了运行这个应用程序的结果。
图1.就绪状态0
当0等于4时
在多个JavaScript函数都使用相同的请求对象时,您需要检查就绪状态0来确保这个请求对象没有正在使用,这种机制会产生问题。
由于readyState==4表示一个已完成的请求,因此您经常会发现那些目前没在使用的处于就绪状态的请求对象仍然被设置成了4——这是因为从服务器返回来的数据已经使用过了,但是从它们被设置为就绪状态之后就没有进行任何变化。
有一个函数abort()会重新设置请求对象,但是这个函数却不是真正为了这个目的而使用的。
如果您必须使用多个函数,最好是为每个函数都创建并使用一个函数,而不是在多个函数之间共享相同的对象。
显然,这并不能为您带来多少好处;需要确保尚未调用open()函数的情况很少。
在大部分Ajax编程的真实情况中,这种就绪状态的唯一用法就是使用相同的XMLHttpRequest对象在多个函数之间生成多个请求。
在这种(不常见的)情况中,您可能会在生成新请求之前希望确保请求对象是处于未初始化状态(readyState==0)。
这实际上是要确保另外一个函数没有同时使用这个对象。
查看正在处理的请求的就绪状态
除了0就绪状态之外,请求对象还需要依次经历典型的请求和响应的其他几种就绪状态,最后才以就绪状态4的形式结束。
这就是为什么您在大部分回调函数中都可以看到if(request.readyState==4)这行代码;它确保服务器已经完成对请求的处理,现在可以安全地更新Web页面或根据从服务器返回来的数据来进行操作了。
要查看这种状态发生的过程非常简单。
如果就绪状态为4,我们不仅要运行回调函数中的代码,而且还要在每次调用回调函数时都输出就绪状态。
清单3给出了一个实现这种功能的例子。
清单3.查看就绪状态
functionupdatePage(){
//Outputthecurrentreadystate
alert("updatePage()calledwithreadystateof"+request.readyState);
}
如果您不确定如何运行这个函数,就需要创建一个函数,然后在Web页面中调用这个函数,并让它向服务器端的组件发送一个请求(例如清单2给出的函数,或本系列文章的第1部分和第2部分中给出的例子)。
确保在建立请求时,将回调函数设置为updatePage();要实现这种设置,可以将请求对象的onreadystatechange属性设置为updatePage()。
这段代码就是onreadystatechange意义的一个确切展示——每次请求的就绪状态发生变化时,就调用updatePage(),然后我们就可以看到一个警告了。
图2给出了一个调用这个函数的例子,其中就绪状态为1。
图2.就绪状态1
您可以自己尝试运行这段代码。
将其放入Web页面中,然后激活事件处理程序(单击按钮,在域之间按tab键切换焦点,或者使用设置的任何方法来触发请求)。
这个回调函数会运行多次——每次就绪状态都会改变——您可以看到每个就绪状态的警告。
这是跟踪请求所经历的各个阶段的最好方法。
浏览器的不一致性
在对这个过程有一个基本的了解之后,请试着从几个不同的浏览器中访问您的页面。
您应该会注意到各个浏览器如何处理这些就绪状态并不一致。
例如,在Firefox1.5中,您会看到以下就绪状态:
∙1
∙2
∙3
∙4
这并不奇怪,因为每个请求状态都在这里表示出来了。
然而,如果您使用Safari来访问相同的应用程序,就应该看到——或者看不到——一些有趣的事情。
下面是在Safari2.0.1中看到的状态:
∙2
∙3
∙4
Safari实际上把第一个就绪状态给丢弃了,也并没有什么明显的原因说明为什么要这样做;不过这就是Safari的工作方式。
这还说明了一个重要的问题:
尽管在使用服务器上的数据之前确保请求的状态为4是一个好主意,但是依赖于每个过渡期就绪状态编写的代码的确会在不同的浏览器上得到不同的结果。
例如,在使用Opera8.5时,所显示的就绪状态情况就更加糟糕了:
∙3
∙4
最后,InternetExplorer会显示如下状态:
∙1
∙2
∙3
∙4
如果您碰到请求方面的问题,这就是用来发现问题的首要之处。
最好的方式是在InternetExplorer和Firefox都进行一下测试——您会看到所有这4种状态,并可以检查请求的每个状态所处的情况。
接下来我们再来看一下响应端的情况。
显微镜下的响应数据
一旦我们理解在请求过程中发生的各个就绪状态之后,接下来就可以来看一下XMLHttpRequest对象的另外一个方面了——responseText属性。
回想一下在上一篇文章中我们介绍过的内容,就可以知道这个属性用来从服务器上获取数据。
一旦服务器完成对请求的处理之后,就可以将响应请求数据所需要的任何数据放到请求的responseText中了。
然后回调函数就可以使用这些数据,如清单1和清单4所示。
清单4.使用服务器上返回的响应
functionupdatePage(){
if(request.readyState==4){
varnewTotal=request.responseText;
vartotalSoldEl=document.getElementById("total-sold");
varnetProfitEl=document.getElementById("net-profit");
replaceText(totalSoldEl,newTotal);
/*图outthenewnetprofit*/
varboardCostEl=document.getElementById("board-cost");
varboardCost=getText(boardCostEl);
varmanCostEl=document.getElementById("man-cost");
varmanCost=getText(manCostEl);
varprofitPerBoard=boardCost-manCost;
varnetProfit=profitPerBoard*newTotal;
/*Updatethenetprofitonthesalesform*/
netProfit=Math.round(netProfit*100)/100;
replaceText(netProfitEl,netProfit);
}
清单1相当简单;清单4稍微有点复杂,但是它们在开始时都要检查就绪状态,并获取responseText属性的值。
查看请求的响应文本
与就绪状态类似,responseText属性的值在整个请求的生命周期中也会发生变化。
要查看这种变化,请使用如清单5所示的代码来测试请求的响应文本,以及它们的就绪状态。
清单5.测试responseText属性
functionupdatePage(){
//Outputthecurrentreadystate
alert("updatePage()calledwithreadystateof"+request.readyState+
"andaresponsetextof'"+request.responseText+"'");
}
现在在浏览器中打开Web应用程序,并激活您的请求。
要更好地看到这段代码的效果,请使用Firefox或InternetExplorer,因为这两个浏览器都可以报告出请求过程中所有可能的就绪状态。
例如在就绪状态2中,就没有定义responseText(请参见图3);如果JavaScript控制台也已经打开了,您就会看到一个错误。
图3.就绪状态为2的响应文本
不过在就绪状态3中,服务器已经在responseText属性中放上了一个值,至少在这个例子中是这样(请参见图4)。
图4.就绪状态为3的响应文本
您会看到就绪状态为3的响应在每个脚本、每个服务器甚至每个浏览器上都是不一样的。
不过,这在调试应用程序中依然是非常有用的。
获取安全数据
所有的文档和规范都强调,只有在就绪状态为4时数据才可以安全使用。
相信我,当就绪状态为3时,您很少能找到无法从responseText属性获取数据的情况。
然而,在应用程序中将自己的逻辑依赖于就绪状态3可不是什么好主意——一旦您编写了依赖于就绪状态3的完整数据的的代码,几乎就要自己来负责当时的数据不完整问题了。
比较好的做法是向用户提供一些反馈,说明在处于就绪状态3时,很快就会有响应了。
尽管使用alert()之类的函数显然不是什么好主意——使用Ajax然后使用一个警告对话框来阻塞用户显然是错误的——不过您可以在就绪状态发生变化时更新表单或页面中的域。
例如,对于就绪状态1来说要将进度指示器的宽度设置为25%,对于就绪状态2来说要将进度指示器的宽度设置为50%,对于就绪状态3来说要将进度指示器的宽度设置为75%,当就绪状态为4时将进度指示器的宽度设置为100%(完成)。
当然,正如您已经看到的一样,这种方法非常聪明,但它是依赖于浏览器的。
在Opera上,您永远都不会看到前两个就绪状态,而在Safari上则没有第一个
(1)。
由于这个原因,我将这段代码留作练习,而没有在本文中包括进来。
现在应该来看一下状态代码了。
深入了解HTTP状态代码
有了就绪状态和您在Ajax编程技术中学习到的服务器的响应,您就可以为Ajax应用程序添加另外一级复杂性了——这要使用HTTP状态代码。
这些代码对于Ajax来说并没有什么新鲜。
从Web出现以来,它们就已经存在了。
在Web浏览器中您可能已经看到过几个状态代码:
∙401:
XX
∙403:
禁止
∙404:
没找到
您可以找到更多的状态代码(完整清单请参见参考资料)。
要为Ajax应用程序另外添加一层控制和响应(以及更为健壮的错误处理)机制,您需要适当地查看请求和响应中的状态代码。
200:
一切正常
在很多Ajax应用程序中,您将看到一个回调函数,它负责检查就绪状态,然后继续利用从服务器响应中返回的数据,如清单6所示。
清单6.忽略状态代码的回调函数
functionupdatePage(){
if(request.readyState==4){
varresponse=request.responseText.split("|");
document.getElementById("order").value=response[0];
document.getElementById("address").innerHTML=
response[1].replace(/\n/g,"
");
}
}
这对于Ajax编程来说证明是一种短视而错误的方法。
如果脚本需要认证,而请求却没有提供有效的证书,那么服务器就会返回诸如403或401之类的错误代码。
然而,由于服务器对请求进行了应答,因此就绪状态就被设置为4(即使应答并不是请求所期望的也是如此)。
最终,用户没有获得有效数据,当JavaScript试图使用不存在的服务器数据时就可能会出现严重的错误。
它花费了最小的努力来确保服务器不但完成了一个请求,而且还返回了一个“一切良好”的状态代码。
这个代码是"200",它是通过XMLHttpRequest对象的status属性来报告的。
为了确保服务器不但完成了一个请求,而且还报告了一个OK状态,请在您的回调函数中添加另外一个检查功能,如清单7所示。
清单7.检查有效状态代码
functionupdatePage(){
if(request.readyState==4){
if(request.status==200){
varresponse=request.responseText.split("|");
document.getElementById("order").value=response[0];
document.getElementById("address").innerHTML=
response[1].replace(/\n/g,"
");
}else
alert("statusis"+request.status);
}
}
通过添加这几行代码,您就可以确认是否存在问题,用户会看到一个有用的错误消息,而不仅仅是看到一个由断章取义的数据所构成的页面,而没有任何解释。
重定向和重新路由
在深入介绍有关错误的内容之前,我们有必要来讨论一下有关一个在使用Ajax时并不需要关心的问题——重定向。
在HTTP状态代码中,这是300系列的状态代码,包括:
∙301:
永久移动
∙302:
找到(请求被重新定向到另外一个URL/URI上)
∙305:
使用代理(请求必须使用一个代理来访问所请求的资源)
Ajax程序员可能并不太关心有关重定向的问题,这是由于两方面的原因:
∙首先,Ajax应用程序通常都是为一个特定的服务器端脚本、servlet或应用程序而编写的。
对于那些您看不到就消失了的组件来说,Ajax程序员就不太清楚了。
因此有时您会知道资源已经移动了(因为您移动了它,或者通过某种手段移动了它),接下来要修改请求中的URL,并且不会再碰到这种结果了。
∙更为重要的一个原因是:
Ajax应用程序和请求都是封装在沙盒中的。
这就意味着提供生成Ajax请求的Web页面的域必须是对这些请求进行响应的域。
因此所提供的Web页面就不能对一个在上运行的脚本生成一个Ajax风格的请求;在上的Ajax应用程序也无法对在netbeans.org上运行的servlets发出请求。
结果是您的请求无法重定向到其他服务器上,而不会产生安全性错误。
在这些情况中,您根本就不会得到状态代码。
通常在调试控制台中都会产生一个JavaScript错误。
因此,在对状态代码进行充分的考虑之后,您就可以完全忽略重定向代码的问题了。
边界情况和困难情况
看到现在,一些新手程序员就可能会这究竟是要讨论什么内容。
有一点事实大家需要知道:
只有不到5%的Ajax请求需要使用诸如2、3之类的就绪状态和诸如403之类的状态代码(实际上,这个比率可能更接近于1%甚至更少)。
这些情况非常重要,称为边界情况(edgecase)——它们只会在一些非常特殊的情况下发生,其中遇到的都是最奇特的问题。
虽然这些情况并不普遍,但是这些边界情况却占据了大部分用户所碰到的问题的80%!
对于典型的用户来说,应用程序100次都是正常工作的这个事实通常都会被忘记,然而应用程序只要一次出错就会被他们清楚地记住。
如果您可以很好地处理边界情况(或困难情况),就可以为再次访问站点的用户提供满意的回报。
错误
一旦接收到状态代码200并且意识到可以很大程度上忽略300系列的状态代码之后,所需要担心的唯一一组代码就是400系列的代码了,这说明了不同类型的错误。
回头再来看一下清单7,并注意在对错误进行处理时,只将少数常见的错误消息输出给用户了。
尽管这是朝正确方向前进的一步,但是要告诉从事应用程序开发的用户和程序员究竟发生了什么问题,这些消息仍然是没有太大用处的。
首先,我们要添加对找不到的页的支持。
实际上这在大部分产品系统中都不应该出现,但是在测试脚本位置发生变化或程序员输入了错误的URL时,这种情况并不罕见。
如果您可以自然地报告404错误,就可以为那些困扰不堪的用户和程序员提供更多帮助。
例如,如果服务器上的一个脚本被删除了,我们就可以使用清单7中的代码,这样用户就会看到一个如图5所示的非描述性错误。
图5.常见错误处理
用户无法判断问题究竟是认证问题、没找到脚本(此处就是这种情况)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 掌握 Ajax 部分 中的高级请求和响应 中的 高级 请求 响应