使用 JavaScript 和 Ajax 发出异步请求在 Web 请求中使用 XMLHttpRequestWord文件下载.docx
《使用 JavaScript 和 Ajax 发出异步请求在 Web 请求中使用 XMLHttpRequestWord文件下载.docx》由会员分享,可在线阅读,更多相关《使用 JavaScript 和 Ajax 发出异步请求在 Web 请求中使用 XMLHttpRequestWord文件下载.docx(21页珍藏版)》请在冰豆网上搜索。
当然这里仍然有请求和响应,只不过都藏到了幕后。
作为用户,体验更加舒适,感觉很像桌面应用程序。
这种新的感受和范型就是当有人提到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对象
<
scriptlanguage="
javascript"
type="
text/javascript"
>
varrequest=newXMLHttpRequest();
/script>
不难吧?
记住,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!
"
);
一定要理解这些步骤:
创建一个新变量request并赋值false。
后面将使用false作为判定条件,它表示还没有创建XMLHttpRequest对象。
增加try/catch块:
尝试创建XMLHttpRequest对象。
如果失败(catch(failed))则保证request的值仍然为false。
检查request是否仍为false(如果一切正常就不会是false)。
如果出现问题(request是false)则使用JavaScript警告通知用户出现了问题。
代码非常简单,对大多数JavaScript和Web开发人员来说,真正理解它要比读写代码花更长的时间。
现在已经得到了一段带有错误检查的XMLHttpRequest对象创建代码,还可以告诉您哪儿出了问题。
应付Microsoft
看起来似乎一切良好,至少在用InternetExplorer试验这些代码之前是这样的。
如果这样试验的话,就会看到图1所示的糟糕情形。
图1.InternetExplorer报告错误
Microsoft参与了吗?
关于Ajax和Microsoft对该领域不断增长的兴趣和参与已经有很多文章进行了介绍。
事实上,据说Microsoft最新版本的InternetExplorer——version7.0,将在2006年下半年推出——将开始直接支持XMLHttpRequest,让您使用new关键字代替所有的Msxml2.XMLHTTP创建代码。
但不要太激动,仍然需要支持旧的浏览器,因此跨浏览器代码不会很快消失。
显然有什么地方不对劲,而InternetExplorer很难说是一种过时的浏览器,因为全世界有70%在使用InternetExplorer。
换句话说,如果不支持Microsoft和InternetExplorer就不会受到Web世界的欢迎!
因此我们需要采用不同的方法处理Microsoft浏览器。
经验证发现Microsoft支持Ajax,但是其XMLHttpRequest版本有不同的称呼。
事实上,它将其称为几种不同的东西。
如果使用较新版本的InternetExplorer,则需要使用对象Msxml2.XMLHTTP,而较老版本的InternetExplorer则使用Microsoft.XMLHTTP。
我们需要支持这两种对象类型(同时还要支持非Microsoft浏览器)。
请看看清单4,它在前述代码的基础上增加了对Microsoft的支持。
清单4.增加对Microsoft浏览器的支持
}catch(trymicrosoft){
try{
request=newActiveXObject("
Msxml2.XMLHTTP"
}catch(othermicrosoft){
Microsoft.XMLHTTP"
}catch(failed){
}
很容易被这些花括号迷住了眼睛,因此下面分别介绍每一步:
使用false作为判断条件,它表示还没有创建XMLHttpRequest对象。
如果失败(catch(trymicrosoft)):
尝试使用较新版本的Microsoft浏览器创建Microsoft兼容的对象(Msxml2.XMLHTTP)。
如果失败(catch(othermicrosoft))尝试使用较老版本的Microsoft浏览器创建Microsoft兼容的对象(Microsoft.XMLHTTP)。
检查request是否仍然为false(如果一切顺利就不会是false)。
这样修改代码之后再使用InternetExplorer试验,就应该看到已经创建的表单(没有错误消息)。
我实验的结果如图2所示。
图2.InternetExplorer正常工作
静态与动态
再看一看清单1、3和4,注意,所有这些代码都直接嵌套在script标记中。
像这种不放到方法或函数体中的JavaScript代码称为静态JavaScript。
就是说代码是在页面显示给用户之前的某个时候运行。
(虽然根据规范不能完全精确地知道这些代码何时运行对浏览器有什么影响,但是可以保证这些代码在用户能够与页面交互之前运行。
)这也是多数Ajax程序员创建XMLHttpRequest对象的一般方式。
就是说,也可以像清单5那样将这些代码放在一个方法中。
清单5.将XMLHttpRequest创建代码移动到方法中
varrequest;
functioncreateRequest(){
}catch(trymicrosoft){
if(!
如果按照这种方式编写代码,那么在处理Ajax之前需要调用该方法。
因此还需要清单6这样的代码。
清单6.使用XMLHttpRequest的创建方法
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;
}
functiongetCustomerInfo(){
varphone=document.getElementById("
phone"
).value;
varurl="
/cgi-local/lookupCustomer.php?
phone="
+escape(phone);
这里没有难懂的地方。
首先,代码创建了一个新变量phone,并把ID为“phone”的表单字段的值赋给它。
清单8展示了这个表单的XHTML,其中可以看到phone字段及其id属性。
清单8.BreakNeckPizza表单
<
body>
p>
imgsrc="
breakneck-logo_4c.gif"
alt="
BreakNeckPizza"
/>
/p>
formaction="
POST"
Enteryourphonenumber:
inputtype="
text"
size="
14"
name="
id="
onChange="
getCustomerInfo();
Yourorderwillbedeliveredto:
divid="
address"
/div>
Typeyourorderinhere:
textareaname="
order"
rows="
6"
cols="
50"
/textarea>
submit"
value="
OrderPizza"
/form>
/body>
还要注意,当用户输入电话号码或者改变电话号码时,将触发清单8所示的getCustomerInfo()方法。
该方法取得电话号码并构造存储在url变量中的URL字符串。
记住,由于Ajax代码是沙箱型的,因而只能连接到同一个域,实际上URL中不需要域名。
该例中的脚本名为/cgi-local/lookupCustomer.php。
最后,电话号码作为GET参数附加到该脚本中:
+escape(phone)。
如果以前没用见过escape()方法,它用于转义不能用明文正确发送的任何字符。
比如,电话号码中的空格将被转换成字符%20,从而能够在URL中传递这些字符。
可以根据需要添加任意多个参数。
比如,如果需要增加另一个参数,只需要将其附加到URL中并用“与”(&
)字符分开[第一个参数用问号(?
)和脚本名分开]。
打开请求
open()是打开吗?
Internet开发人员对open()方法到底做什么没有达成一致。
但它实际上并不是打开一个请求。
如果监控XHTML/Ajax页面及其连接脚本之间的网络和数据传递,当调用open()方法时将看不到任何通信。
不清楚为何选用了这个名字,但显然不是一个好的选择。
有了要连接的URL后就可以配置请求了。
可以用XMLHttpRequest对象的open()方法来完成。
该方法有五个参数:
request-type:
发送请求的类型。
典型的值是GET或POST,但也可以发送HEAD请求。
url:
要连接的URL。
asynch:
如果希望使用异步连接则为true,否则为false。
该参数是可选的,默认为true。
username:
如果需要身份验证,则可以在此指定用户名。
该可选参数没有默认值。
password:
如果需要身份验证,则可以在此指定口令。
通常使用其中的前三个参数。
事实上,即使需要异步连接,也应该指定第三个参数为“true”。
这是默认值,但坚持明确指定请求是异步的还是同步的更容易理解。
将这些结合起来,通常会得到清单9所示的一行代码。
清单9.打开请求
request.open("
GET"
url,true);
一旦设置好了URL,其他就简单了。
多数请求使用GET就够了(后面的文章中将看到需要使用POST的情况),再加上URL,这就是使用open()方法需要的全部内容了。
挑战异步性
本系列的后面一篇文章中,我将用很多时间编写和使用异步代码,但是您应该明白为什么open()的最后一个参数这么重要。
在一般的请