4.2 XMLHttpRequest对象的常见方法和属性

XMLHttpRequest对象提供了对HTTP协议的完全访问,包括做出POST和HEAD请求以及普通的GET请求的能力。XMLHttpRequest可以同步或异步返回Web服务器的响应。尽管命名中有XML,但是它并不仅限于和XML文档一起使用——它可以接收任何形式的文本文档。它是AJAX Web应用程序架构的关键组成部分。

简单地说,AJAX主要通过JavaScript操作XMLHttpRequest 对象来向服务器发异步请求,获得服务器给的数据后,再由JavaScript根据获得的数据来操作DOM,从而达到更新页面的目的,如图4-3所示。

图4-3 AJAX流程

其中关键的一步是从服务器请求并获得数据,要清楚这些就必须对XMLHttpRequest对象的常见方法和属性有所了解。

4.2.1 XMLHttpRequest对象方法

表4-1列出了XMLHttpRequest最常见的几个方法及说明。

表4-1 XMLHttpRequest对象的常见方法

与POST相比,GET更简单也更快,并且在大部分情况下都能用。然而,在以下情况中,请使用POST请求:


● 不能使用缓存文件时(更新服务器上的文件或数据库)。

● 向服务器发送大量数据时(POST没有数据量限制)。

● 发送包含未知编码字符的用户输入时(POST比GET更稳定、更可靠、更一致)。

【范例4-4】中的第50行代码可能得到的是缓存的结果。为了避免这种情况,可以给URL添加一个唯一的标识:

        URL:"4-4.txt? t="+Math.random() ,

其实就是添加了一个t参数,这个参数每次都会产生一个随机的、不相同的值,且这个参数会被发送给服务器端并可以被接收,如果要传递更多信息,还可以添加更多的参数:

        URL:"4-4.txt? t="+Math.random()+"&user=z3f&homepage=www.z3f.me",

前面说到,POST更可靠的原因就在于GET 通过这样的方式传递信息的时候有最大长度的限制,IE 9以前的版本最大只能接受2083个字符。URL的长度不仅浏览器会限制,各种Web服务器也会限制,为了避免产生未知的问题,不建议在URL中传递太多数据,尤其是传递中文信息时,通过UTF-8编码的中文会占用9个字符,也就是说最多传递200个左右的字符。

下面再来看一下POST请求,对【范例4-4】中的代码修改一下即可运行:

        eg.AJAX({TYPE:"POST",

AJAX模拟表单POST提交请求就不用担心数据长度的限制了。但过大的数据,比如超过几吉字节的文件,就会导致浏览器卡死甚至崩溃。

最后一个参数是async,在我们的例子中总是true,意思是JavaScript无须等待服务器的响应就可以做更多的事情,可通过下面的【范例4-5】来理解。

【范例4-5 AJAX同步请求】

    1.      <html>
    2.       <head>
    3.         <title>hello ajax sync</title>
    4.       </head>
    5.       <body>
    6.               <div id="myajax">hello world! </div>
    7.              <button type="button" id="ajaxBtn">通过 AJAX 同步改变内容</button>
    8.               <script src="eg.lib.js"></script>
    9.       </body>
    10.     </html>
    11.     <script>
    12.    (function(){  //避免全局污染,将操作放在闭包里
    13.             var ajaxBtn = eg.$("ajaxBtn");
                  //取得username 的DOM 对象,eg.$方法定义在eg.lib.js 中,详见第2 章范例
    14.             //给userName 对象绑定一个onkeyup 事件,eg.addListener 方法
                    定义在eg.lib.js 中,详见第2 章范例
    15.             eg.addListener(ajaxBtn, "click", function(){
    16.                     eg.AJAX({TYPE:"GET", //AJAX 请求类型
    17.                             URL:"4-4.txt", //AJAX 请求的URL,该文件只有"hello ajax"
                                字符串的纯文本
    18.                             ISASYN:false  //是否异步
    19.                     }, function(data){//定义AJAX 请求成功后的callback 回调函数
    20.                             //元素myajax 原本的hello world!会变成hello ajax
                                  eg.$("myajax").innerHTML = data;
    21.                      });
    22.             });
    23.     })();
    24.     </script>

通过观察【范例4-4】第30~42行的代码可以发现,同步和异步相比,少了onreadystatechange回调函数的定义,把主要操作代码直接移植到最后,这似乎更符合思维方式,如果服务端请求要很久才能响应,那么用户的浏览器在此就会卡住——处于假死状态。这就是AJAX异步存在的价值,如果读者是从传统编程语言迁移过来的,就要改变一下思维方式,【范例4-5】这样的同步调用方式不推荐在AJAX中使用,一些极端的特殊情况除外。

4.2.2 XMLHttpRequest对象属性

表4-2列出XMLHttpRequest比较重要的几个属性及说明,值得注意的是onreadystatechange和responseText。

表4-2 XMLHttpRequest对象的常见属性

在程序中onreadystatechange回调函数一般会被触发4次,对应着readyState的每个变化,也正因如此开发者才可以根据自己的需要对每一个变化进行处理。在前面的范例中都是使用responseText属性,如果来自服务器的响应是XML,虽然越来越少的Web应用程序还在使用XML数据交换格式,但如果要用XML,就要使用responseXML属性,可通过【范例4-6】来理解它的用法。

【范例4-6 AJAX获取XML内容】

    1.      <html>
    2.       <head>
    3.         <title>hello ajax xml</title>
    4.       </head>
    5.       <body>
    6.               <div id="myajax">hello world! </div>
    7.              <button type="button" id="ajaxBtn">通过 AJAX 获取xml 内容</button>
    8.               <script src="eg.lib.js"></script>
    9.       </body>
    10.     </html>
    11.     <script>
    12.    (function(){                                  //避免全局污染,将操作放在闭包里
    13.             var ajaxBtn = eg.$("ajaxBtn"); //取得username 的DOM 对象,
                  eg.$方法定义在eg.lib.js,详见第2 章范例
    14.             //给userName 对象绑定一个onkeyup 事件,eg.addListener 方法定义在
                    eg.lib.js,详见第2 章范例
    15.             eg.addListener(ajaxBtn, "click", function(){
    16.                     eg.AJAX({TYPE:"GET", //AJAX 请求类型
    17.                             URL:"4-6.xml", //AJAX 请求的URL,该文件就是范例4-2 的代码
    18.                             ISASYN:true   //是否异步
    19.                     }, function(txt, xml){//定义AJAX 请求成功后的callback 回调函数
    20.                    var root = xml.getElementsByTagName("name");
    21.                              eg.$("myajax").innerHTML = root[0].
                                childNodes[0]. nodeValue;
    22.                      });
    23.             });
    24.     })();
    25.     </script>

变量url请求的文件4-6.xml内容就是【范例4-2】的XML格式代码,图4-4是其运行效果。

图4-4 AJAX获取XML内容

如果要达到相同效果,使用JSON数据交换格式的代码如【范例4-7】所示。

【范例4-7 AJAX获取JSON内容】

 
    1.      <html>
    2.       <head>
    3.         <title>hello ajax JSON</title>
    4.       </head>
    5.       <body>
    6.               <div id="myajax">hello world! </div>
    7.              <button type="button" id="ajaxBtn">通过AJAX 获取JSON 内容</button>
    8.               <script src="eg.lib.js"></script>
    9.       </body>
    10.     </html>
    11.     <script>
    12.      (function(){                                 //避免全局污染,将操作放在闭包里
    13.             var ajaxBtn = eg.$("ajaxBtn");
                  //取得username 的DOM 对象,eg.$方法定义在eg.lib.js,详见第2 章范例
    14.             //给userName 对象绑定一个onkeyup 事件,eg.addListener 方法定义
                    在eg.lib.js,详见第2 章范例
    15.             eg.addListener(ajaxBtn, "click", function(){
    16.                     eg.AJAX({TYPE:"GET", //AJAX 请求类型
    17.                              URL:"4-7.txt",
                                  //AJAX 请求的URL,该文件就是范例4-3 的JSON 代码
    18.                             ISASYN:true     //是否异步
    19.                     }, function(txt, xml){  //定义AJAX 请求成功后的callback 回调函数
    20.                              var json = new Function("return "+txt)();
            //简单的JSON 字符串转换为JavaScript 对象
    21.                             eg.$("myajax").innerHTML = json.name;    //输出用户名
    22.                      });
    23.             });
    24.     })();
    25.     </script>

运行效果见图4-4右半部分。如果面对更复杂的数据结构,使用JSON会体现出更高的效率,编写的代码也更加容易和简洁。