XMLHttpRequest——Ajax 时代的到来

开发 Ajax 应用程序的难度在于,需要对 DOM、CSS 和 JavaScript 都很熟悉。

本文目的不在于讨论如何去使用 XMLHttpRequest 对象,因为现在的 Ajax 框架很容易做到,只是从底层去看那些 Ajax 框架。像下面的代码,用 jQuery 只要一两个语句就搞定了。但这不能说明了解 XMLHttpRequest 和它的演化,一点意义都没有。

var oXHR = new XMLHttpRequest();
oXHR.onreadystatechange = function() {
// TODO
}
oXHR.open("GET", "gAddress.txt", true);
oXHR.send(null);

本文内容

  • 引入
  • XMLHttpRequest 概述
  • XMLHttpRequest 演化
  • 演示:使用 XMLHttpRequest 对象获取和显示来自服务器的数据

 

引入

隐藏 iframe 技术是第一个异步模型。但它几个缺点:

  • 无法向域外的服务器发送请求。这是因为受到浏览器安全机制限制,JavaScript 只能与同一个域的表单交互,即使是来自于子域的页面也无法访问(如 p2p.wrox.com 与 www.wrox.com)。
  • 对背后所发生的 HTTP 请求缺乏足够的信息。它完全依赖于返回的正确页面。也就是说,如果隐藏帧的页面加载失败,不会向用户提示出错信息。主页面要么等待直到调用适当的 JavaScript 函数,要么设置一个较长的超时时间,最后,实在不能成功载入页面,只能显示一条信息,给用户一个安慰。

还好,我们有另一个选择——XMLHttpRequest。可以解决隐藏帧技术存在的问题。

 

XMLHttpRequest 概述

XMLHttpRequest 解决了隐藏 iframe 技术什么问题:

  • 提供足够的 HTTP 请求信息。回想一下现在的 Ajax 框架。不仅可以访问请求和响应首部,还能访问 HTTP 状态码,这使得可以判断请求处理是否成功。

XMLHttpRequest 也有不足之处:

  • 不像隐藏帧技术,当发出调用时,并没有浏览器的历史记录保存下来。也就是说,浏览器的后退和前进按钮无效。因此,很多 Ajax 应用程序将 XHR 和隐藏帧技术结合起来,创建一个更加可用的用户界面;
  • 如果用户将你的页面设置为特定的安全区域,该区域禁用 ActiveX 控件,这只在 IE 上,将无法访问 XHR 对象。此时,只能使用隐藏帧技术。
  • XHR 在跨域通信时也会受到限制。不过,这可以通过服务器代理解决。

 

XMLHttpRequest 演化

  • 微软在 IE 5.0 引入 MSXML ActiveX 程序库,用于创建 XMLHttp 对象,使得开发人员在应用程序的任何地方初始化 HTTP 请求。微软直到 IE 7 才创建他们自己的原生 XMLHttpRequest 对象。虽然,微软的 IE 5.5/6 支持 XMLHttpRequest,但是没有这个对象的本机版本。
  • 接下来,Mozilla Firefox 也实现了 XMLHttp 功能。他们创建了一个原生的 JavaScript 对象 XMLHttpRequest。
  • 之后,Safari 1.2 和 Opera 7.6 浏览器也复制了 Mozilla 的实现。

现在,这四种浏览器都提供了对原生 XMLHttpRequest 对象的支持。

 

演示:使用 XMLHttpRequest 对象获取和显示来自服务器的数据

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>My First Ajax Script</title>
 
    <script type="text/javascript">
   1:  
   2:         window.onload = initAll;
   3:         var oXHR = false;
   4:  
   5:         function initAll() {
   6:             document.getElementById("makeTextRequest").onclick = getNewFile;
   7:             document.getElementById("makeXMLRequest").onclick = getNewFile;
   8:         }
   9:  
  10:         function getNewFile() {
  11:             makeRequest(this.href);
  12:             return false;
  13:         }
  14:  
  15:         function makeRequest(url) {
  16:             if (window.XMLHttpRequest != undefined) {
  17:                 oXHR = new XMLHttpRequest();
  18:             }
  19:             else {
  20:                 if (window.ActiveXObject) {
  21:                     var aVersions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0"];
  22:                     for (var i = 0; i < aVersions.length; i++) {
  23:                         try {
  24:                             oXHR = new ActiveXObject(aVersions[i]);
  25:                         }
  26:                         catch (e) { }
  27:                     }
  28:                 }
  29:             }
  30:  
  31:             if (oXHR) {
  32:                 oXHR.onreadystatechange = function() {
  33:                     if (oXHR.readyState == 4) {
  34:                         var outMsg;
  35:                         if (oXHR.status == 200 || oXHR.status == 304) {
  36:                             outMsg =
  37:                             (oXHR.responseXML && oXHR.responseXML.contentType == "text/xml") ? oXHR.responseXML.getElementsByTagName("choices")[0].textContent : oXHR.responseText;
  38:                         }
  39:                         else {
  40:                             outMsg = "请求发生错误...XHR 状态: " + oXHR.status;
  41:                         }
  42:                         document.getElementById("updateArea").innerHTML = outMsg;
  43:                     }
  44:                 };
  45:                 oXHR.open("GET", url, true);
  46:                 oXHR.send(null);
  47:             }
  48:             else {
  49:                 document.getElementById("updateArea").innerHTML = "不能创建一个 XMLHttpRequest 对象.";
  50:             }
  51:         }
  52:     
</script>
 
</head>
<body>
    <p>
        <a id="makeTextRequest" href="gAddress.txt">请求 TXT 文件</a><br />
        <a id="makeXMLRequest" href="us-states.xml">请求 XML 文件</a></p>
    <div id="updateArea">
        &nbsp;</div>
</body>
</html>

运行界面:

5{9WJ3[C~NS)O(OBD)2[H)X

图1 初始界面

1YID[CKOKF)FWG1EYS[9K{L

图2 点击“请求 TXT 文件”后

以下几点值得说明:

1,第 12 行,当函数返回时,告诉浏览器我们不希望装载新的页面;

2,第 16 ~ 29 行,为兼容浏览器尝试创建 XHR 对象,看上去有点麻烦,其实你早以不必这么写。

"oXHR = new ActiveXObject(…)" 是 IE 7 前的版本,其中,MSXML2.XMLHttp.6.0 是针对 IE 9,其他版本的 IE,微软推荐使用 3.0 版本;

"oXHR = new XMLHttpRequest()" 支持现在所有浏览器,所以可以一直这样创建 XHR 对象。

3,第32、44、45 行,当创建一个 XHR 对象后,总是要做三件事,或者说至少两件:

  • 设置 onreadystatechange 事件。
  • 调用 open() 创建请求。
open(request type, URL, async)

1)请求类型(request type):字符串。GET 或 POST。

2)地址URL:字符串。请求的 URL。

3)异步async:布尔型。fasle 为同步发送请求;true 为异步发送请求。也就是说,我们是否会等待。

同步请求会让 JavaScript 等待接收到响应后再继续执行剩下代码。因此,若响应时间很长,用户在浏览器收到响应前,将无法与其交互。

Ajax 应用程序最佳实践是,使用异步请求来实现常规数据的获取(GET 方式),使用同步请求与服务器之间发送和接收简单的消息(POST 方式)。

如果使用同步请求,则不用设置 onreadystatechange 事件。

  • 调用 send() 发送请求。

4,第 33 ~ 43 行,是客户端获得响应后的处理。

  • "oXHR.readyState == 4" 是所有数据都已经收到,连接已经关闭。当然还有其他状态,但是由于 的实现不同,唯一可靠的 readyState 值是4。每当 readyState 值发生变化时,就将触发 readyStateChange 事件。只判断 oXHR.readyState 是不够。
  • "oXHR.status == 200" HTTP 响应状态码,表示成功。如果状态为 304,即 "oXHR.status == 304",则 responseText 和 responseXML 属性仍然包含正确的数据。只是该数据来自于浏览器缓存,而不是服务器。

 

下载 Demo

posted @ 2011-10-06 10:16  船长&CAP  阅读(2473)  评论(0编辑  收藏  举报
免费流量统计软件