AJAX 学习笔记(1) XMLHttpRequest对象概述

XMLHttpRequest对象概述
在使用XMLHttpRequest对象发送请求和处理响应之前,必须先用JavaScript创建一个XMLHttpRequest对象。由于XMLHttpRequest不是一个W3C标准,所以可以采用多种方法使用JavaScript来创建XMLHttpRequest的实例。Internet Explorer把XMLHttpRequest实现为一个ActiveX对象,其他浏览器(如Firefox、Safari和Opera)会把它实现为一个本地JavaScript对象。由于存在这样一些差别,JavaScript代码中必须包含有关的逻辑,从而使用ActiveX技术或者使用本地JavaScript技术来创建XMLHttpRequest的一个实例。
很多人可能还记得从前的那段日子,那时不同浏览器上的JavaScript和DOM实现简直千差万别,听了上面这段话之后,这些人可能又会不寒而栗。幸运的是,在这里为了明确该如何创建XMLHttpRequest对象的实例,并不需要那么详细地编写代码来区别浏览器类型。你要做的只是检查浏览器是否提供对ActiveX对象的支持。如果你的浏览器支持ActiveX对象,就使用ActiveX来创建XMLHttpRequest对象。否则,就要使用本地JavaScript对象技术来创建。代码清单2-1展示了编写跨浏览器的JavaScript代码来创建XMLHttpRequest对象实例是多么的简单。
代码清单2-1 创建XMLHttpRequest对象的一个实例
var xmlHttp;
function createXMLHttpRequest() {
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject(”Microsoft.XMLHTTP”);
}
else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
}
可以看到,创建XMLHttpRequest对象相当容易。首先,要创建一个全局作用域变量xmlHttp来保存这个对象的引用。createXMLHttpRequest方法完成创建XMLHttpRequest实例的具体工作。这个方法中只有简单的分支逻辑(选择逻辑),来确定如何创建对象。对window.ActiveXObject的调用会返回一个对象,也可能返回null,if语句会把调用返回的结果看作是true或false(如果返回对象则为true,返回null则为false),以此指示浏览器是否支持ActiveX控件,相应地得知浏览器是不是Internet Explorer。如果确实是,则实例化ActiveXObject的一个新实例来创建XMLHttpRequest对象,并传入一个串指示要创建何种类型的ActiveX对象。在这个例子中,为构造函数提供的串是Microsoft.XMLHTTP,这说明你想创建XMLHttpRequest的一个实例。
如果window.ActiveXObject调用失败(返回null),JavaScript就会转到else语句分支,确定浏览器是否把XMLHttpRequest实现为一个本地JavaScript对象。如果存在window.XMLHttpRequest,就会创建XMLHttpRequest的一个实例。
由于JavaScript具有动态类型特性,而且XMLHttpRequest实现在不同浏览器上是兼容的,所以可以以同样的方式访问XMLHttpRequest实例的属性和方法,而不论这个实例是如何创建的。这就大大简化了开发过程,而且在JavaScript中也不必编写特定于浏览器的逻辑。

方法和属性
表2-1显示了XMLHttpRequest对象的一些典型方法。不要担心;稍后就会详细介绍这些方法。
表2-1 标准XMLHttpRequest操作


方法      描述
 
abort()     停止当前请求。(译者注:原文此处不对)
getAllResponseHeaders()   把HTTP请求的所有响应首部作为键/值对返回。
getResponseHeader(”header”)   返回指定首部的串值。
open(”method”, “url”)   建立对服务器的调用。
     method(方法)参数可以是GET、POST或PUT。
     url参数可以是相对URL或绝对URL。这个方法还包括3个可选的参数.
send(content)     向服务器发送请求。
setRequestHeader(”header”, “value”) 把指定首部设置为所提供的值。在设置任何首部之前必须先调用open()。

下面来更详细地讨论这些方法。
void open(string method, string url, boolean asynch, string username, string password):这个方法会建立对服务器的调用。这是初始化一个请求的纯脚本方法。它有两个必要的参数,还有3个可选参数。要提供调用的特定方法(GET、POST或PUT),还要提供所调用资源的URL。另外还可以传递一个Boolean值,指示这个调用是异步还是同步的,默认值为true,这表示请求本质上是异步的。如果这个参数为false,处理就会等待,直到从服务器返回响应为止。由于异步调用是使用Ajax的主要优点之一,所以倘若将这个参数设置为false,从某种程度上讲与使用XMLHttpRequest对象的初衷不太相符。不过,前面已经说过,在某些情况下这个参数设置为false也是有用的,比如在持久存储页面之前你可能想先验证用户的输入。最后两个参数不说自明,允许你指定一个特定的用户名和口令。
void send(content):这个方法具体向服务器发出请求。如果请求声明为异步的,这个方法就会立即返回,否则它会等待,直到接收到响应为止。参数是可选的,可以是一个DOM对象的实例、一个输入流,或者是一个串。传入这个对象的内容会作为请求体的一部分发送。
void setRequestHeader(string header, string value): 这个方法为HTTP请求中一个给定的首部设置值。它有两个参数,第一个串表示要设置的首部,第二个串表示要在首部中放置的值。需要说明,这个方法必须在open()之后才能调用。在所有这些方法中,最有可能用到的就是open()和send()。XMLHttpRequest对象还有许多属性,在设计Ajax交互时这些属性非常有用。
void abort(): 顾名思义,这个方法就是要停止请求。
string getAllResponseHeaders(): 这个方法的核心功能对Web应用开发人员应该很熟悉了,它会返回一个串,其中包含HTTP请求的所有响应首部。首部包括Content-Length、Date和URI。
string getResponseHeader(string header): 这个方法与getAllResponseHeaders()是对应的,不过它有一个参数来表示你希望得到哪一个首部值,并且会把这个值作为一个串返回。
除了这些标准方法,XMLHttpRequest对象还提供了许多属性,如表2-2所示。处理XMLHttpRequest时可以大量使用这些属性。
表2-2 标准XMLHttpRequest属性


属性   描述
 
onreadystatechange  每个状态改变时都会触发这个事件处理器,通常会调用一个JavaScript函数。
readyState   请求的状态。有5个可取值:
   0 = 未初始化,1 = 正在加载, 2 = 已加载, 3 = 交互中, 4 = 完成。
responseText   服务器的响应,表示为一个串。
responseXML   服务器的响应,表示为XML。这个对象可以解析为一个DOM对象。
status    服务器的HTTP状态码(200对应OK,404对应Not Found(未找到),等等)
statusText   HTTP状态码的相应文本(OK或Not Found(未找到)等等)。

一个交互示例
看到这里,你可能想知道典型的Ajax交互是什么样子。图2-1显示了Ajax应用中标准的交互模式。
图见P26-1
图2-1 标准Ajax交互
图中文字对照:
Ajax-Enabled Web Application:使用Ajax的Web应用
Web Container:Web容器
Event:事件
Client:客户
Server:服务器
Server Resource:服务器资源
Data Store:数据库
不同于标准Web客户中所用的标准请求/响应方法,Ajax应用的做法稍有点差别。
1. 一个客户端事件触发一个Ajax事件。从简单的onchange事件,到某个特定的用户动作,很多这样的事件都可以触发Ajax事件。可以有如下的代码:

2. 创建XMLHttpRequest对象的一个实例。使用open()方法建立调用,并设置URL以及所希望的HTTP方法(通常是GET或POST)。请求实际上通过一个send()方法调用触发。代码可能如下所示:
var xmlHttp;
function validateEmail() {
var email = document.getElementById(”email”);
var url = “validate?email=” + escape(email.value);
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject(”Microsoft.XMLHTTP”);
}
else if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
xmlHttp.open(”GET”, url);
xmlHttp.onreadystatechange = callback;
xmlHttp.send(null);
}
3. 向服务器做出请求。可能会调用一个servlet、一个CGI脚本,或者使用任何其他服务器端技术。
4. 服务器可以做你想做的事情,包括访问数据库,甚至访问另一个系统。
5. 请求返回到浏览器。Content-Type首部设置为text/xml—XMLHttpRequest对象只能处理text/html类型的结果。在另外一些的情况下,响应可能更为复杂,还包括JavaScript、DOM管理以及其他相关的技术。需要说明,你还需要设置另外一些首部,使浏览器不会在本地缓存结果。为此可以使用下面的代码:
response.setHeader(”Cache-Control”, “no-cache”);
response.setHeader(”Pragma”, “no-cache”);[1]
6. 在这个例子中,XMLHttpRequest对象配置为处理返回时要调用callback()函数。这个函数会检查XMLHttpRequest对象的readyState属性,然后查看服务器返回的状态码。如果一切正常,callback()函数就会在客户端上做些有意思的工作。以下就是一个典型的回调方法:
function callback() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
//do something interesting here
}
}
}
可以看到,这与正常的请求/响应模式有所不同,但对Web开发人员来说,并不是完全陌生的。显然,在创建和建立XMLHttpRequest对象时还可以做些事情,另外当“回调”函数完成了状态检查之后也可以有所作为。一般地,你会把这些标准调用包装在一个库中,以便在整个应用中使用,或者可以使用Web上提供的库。这个领域还很新,但是开源群体中已经如火如荼地展开了许多这方面的工作。
通常,网上有许多框架和工具包能负责基本的连接和浏览器抽象,有些还增加了用户界面组件。有一些纯粹基于客户,还有一些需要服务器上的工作。这些框架很多只是刚刚才开始开发,或者才发布不久;情况还在不断发生变化,经常会有新的库和新的版本出现。随着这个领域日渐成熟,孰优孰劣就会很清楚了。一些比较成熟的库包括libXmlRequest、RSLite、sarissa、JavaScript对象注解(JavaScript Object Notation,JSON)、JSRS、直接Web远程通信(Direct Web Remoting,DWR)和Rails的Ruby。这个领域日新月异,所以应当适当地配置你的RSS收集器,及时收集有关Ajax的所有网站上的信息!

GET vs. POST
你可能不清楚GET和POST之间有什么区别,不知道在这两种方法中该使用哪一个。理论上讲,如果请求是幂等的(idempotent),就可以使用GET,所谓幂等是指多个同样的请求返回的结果也一样。实际上,相应的服务器方法可能会以某种方式修改状态,所以一般情况下这是不成立的。这只是一种标准。更实际的区别在于负载的大小,在许多情况下,尽管能随URL向服务器发送数据,但浏览器和服务器会限制URL的长度。一般来讲,可以使用GET从服务器获取数据;换句话说,要避免使用GET调用修改服务器上的状态。
一般地,要修改服务器上的状态时,就应当使用POST方法。不同于GET,要设置XMLHttpRequest对象的Content-Type首部,如下所示:
xmlHttp.setRequestHeader(”Content-Type”, “application/x-www-form-urlencoded”);
与GET不同,POST不会限制发送给服务器的负载的大小, 而且POST请求不能保证是幂等的。
你做的大多数请求可能都是GET请求,不过,如果需要,也完全可以使用POST。

远程脚本
我们已经介绍了Ajax,下面来简单谈谈远程脚本。你可能会问“Ajax有什么大不了的?我早就用IFRAME做过同样的事情”。实际上,我们自己也曾用过这种方法。从前所做的一般称为远程脚本(remote scripting),很多人认为这只是一种修修补补。不过,这确实提供了一种能避免页面刷新的机制。

远程脚本概述
基本说来,远程脚本是一种远程过程调用。可以像一个正常的Web应用一样与服务器交互,但是不用刷新整个页面。与Ajax类似,可以调用任何服务器端技术来接收请求、处理请求并返回一个有意义的结果。不光是服务器端有很多选择,客户端同样有许多实现远程脚本的选择。可以在应用中嵌入一个Flash动画、一个Java applet,或者一个ActiveX组件。甚至可以使用XML-RPC,但是这种方法太过复杂,因此除非你对这种技术确实很了解,否则这种方法不太合适。实现远程脚本的通常做法是将脚本与一个IFRAME(隐藏或不隐藏)结合,由服务器返回 JavaScript,然后再在浏览器中运行这个JavaScript。
Microsoft提供了自己的远程脚本解决方案,并聪明地称之为Microsoft远程脚本(Microsoft Remote Scripting,MSRS)。采用这种方法,可以像调用本地脚本一样调用服务器脚本。页面中嵌入一个Java applet,以便与服务器通信,在一个.asp页面中放置服务器端脚本,并用一个.htm文件管理客户端的布局摆放。在Netscape和Internet Explorer 4.0及更高版本上都可以使用Microsoft的这种解决方案。可以同步调用,也可以异步调用。不过,这种解决方案需要Java,这意味着可能需要再安装Java,而且还需要Internet Information Services(IIS),因此会限制服务器端的选择。
Brent Ashley为远程脚本创建了两个免费的跨平台库。 JSRS是一个客户端JavaScript库,充分利用了DHTML向服务器做远程调用。相当多的操作系统和浏览器上都能使用JSRS。如果采用一些常用的流行服务器端实现(如 PHP、Python和Perl CGI),一般都能在你的网站上安装并运行JSRS。Ashley免费提供了JSRS,而且还可以从他的网站(www.ashleyit.com/rs/main.htm)上得到源代码。
如果你觉得JSRS太过笨重,Ashley还创建了RSLite,这个库使用了cookie,仅限于发送少量的数据,只能做简单的调用,不过大多数浏览器都能提供支持。

远程脚本的一个例子
为了进行比较,这里向你展示如何使用IFRAME来实现类Ajax的技术。这非常简单,而且过去我们就用过这种方法(在XMLHttpRequest问世之前)。这个例子并没有真正调用服务器,只是想让你对如何使用IFRAME实现远程脚本有所认识。
这个例子包括两个文件:iframe.html(见代码清单2-2)和server.html(见代码清单2-3)。server.html模拟了本应从服务器返回的响应。

代码清单 iframe.html文件
<html>
 <head>
  <title>Example of remote scripting in an IFRAME</title>
 </head>
 <script tyep="text/javascript">
 function handleResponse() {
 alert('this function is called from server.html');
 }
 </script>
 <body>
 <h1>Remote scripting with an IFRAME</h1>
 
 <iframe id="beforexhr" name="beforxhr" style="width:0px; height:0px; border:0px" scr="blank.html"></iframe>

 <a href="server.html" target="beforexhr">call the server</a>
 </body>
</html>

代码清单 server.html文件
<html>
 <head>
  <title>the server</title>
 </head>
 <script tyep="text/javascript">
 window.parent.handleResponse();
 </script>
 <body>
 </body>
</html>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值