创建 XMLHttpRequest 对象


Ajax 这个名词是由Jesse James Garrett提出,在他发表的〈Ajax: A New Approach to Web Applications〉 中谈到 Google Suggest 与 Google Maps 使用到的技术,是他们在Adaptive Path中称之为 Ajax 的新方法:

Google Suggest and Google Maps are two examples of a new approach to web applications that we at Adaptive Path have been calling Ajax. The name is shorthand for Asynchronous JavaScript + XML, and it represents a fundamental shift in what’s possible on the Web.

文中表示,Ajax 是非同步 JavaScript 结合 XML 的概念,XML 是用来交换结构化数据,但事实上,并非唯一可用的格式。

Ajax 的核心概念为非同步,为何要非同步?传统表单提交、超链结点选,浏览器会有默认的处理方式,也就是以同步方式传送请求,接着等待服务器响应数据,然后进行换页动作,在数据提交期间,使用者只能等待最新的画面响应,中间若作了其它的页面操作,浏览器可能会放弃原有的请求,就算在数据响应之后,使用者 面对的是全新的一个页面,即使使用者真正所作的只是会更新画面中某个局部。

如果可以把请求与响应改为非同步进行,也就是发出请求后,浏览器无需苦等服务器的响应,而可以让使用者对浏览 器中的 Web 应用程序进行其它的操作,又不会中断原本的请求,当服务器终于处理完请求并送出响应,而浏览器接收到响应时,再回过头来调用浏览器所设定的对应 动作进行处理,方式是可以利用 DOM 操作更新画面中的某些局部,那么就开启了各种可能的互动模式。

目前来说,在标准浏览器中使用XMLHttpRequest来创建非同步对象,可以如下调用创建非同步对象:

let request = new XMLHttpRequest();

基本上XMLHttpRequest可用的几个方法如下:

  • void open(string method, string url[, boolean asynch, string username, string password]) 开启对伺服端的连结;method 为 HTTP 请求方式('GET'、'POST'、'HEAD' 等);url 为伺服端地址,如果是 GET 的话,可加上请求参数与值;asynch 为非同步设定,默认是 true,表示使用非同步方式,username、password 视伺服端有无要求验证而设置。
  • void setRequestHeader(string header, string value) 为 HTTP 请求设定一个标头值,在调用 open 之后调用,通常在 open 的 method 参数为 'POST' 时使用。
  • void send(content) 对伺服端传送请求,open 的 method 为 'GET' 时,content 设为 null,'POST' 时 content 可放字符串、XML、JSON 格式的内容,会放在 POST 本体中发送。在早期,浏览器不一定支持全部的 HTTP 方法。
  • void abort() 用来中断请求。
  • string getAllResponseHeaders() 返回一个字符串,其中包含 HTTP 请求的所有响应标头。
  • string getResponseHeader(string header) 返回一个字符串,其中包含指定的响应标头值。

open方法的第三个参数通常保留默认置true,若想以同步方式,可以设为false。若想知道目前请求对象状态,可以在调用open方法之前,对onreadystatechange设置处理器函数。只要有状态变化,则会调用所设置的处理器函数。

通常会在onreadystatechange的处理器函数中,侦测XMLHttpRequest对象的状态,状态可借由readyState特性获取,这特性会有 0 到 4 的变化,代表各个处理阶段,常数可透过XMLHttpRequest上的常数名称获取::

  • XMLHttpRequest.UNSENT 常数值 0,XMLHttpRequest 对象已构造。
  • XMLHttpRequest.OPENED 常数值 1,已成功调用 open 方法,在这个状态下,可以使用 setRequestHeader,而后调用 send 方法。
  • XMLHttpRequest.HEADERS_RECEIVED 常数值 2,在调用过 send 方法且接收到响应标头的状态。
  • XMLHttpRequest.LOADING 常数值 3,正在接收响应本体。
  • XMLHttpRequest.DONE 常数值 4,伺服端响应结束,可能是数据传输完成,或者是传送过程因发生错误而中断(例如侦测到无限重导)。

通常只会对readyStateXMLHttpRequest.DONE时作处理,XMLHttpRequest对象的status表示 HTTP 响应状态码,一个例子如下:

let request = new XMLHttpRequest();
request.onreadystatechange = function(evt) {
    let req = evt.target;
    if(req.readyState === XMLHttpRequest.DONE && req.status === 200) {
        // 对成功响应作处理
    }
};
request.open('GET', 'data.txt');
request.send(null);

(偶而地,也会针对XMLHttpRequest.LOADING来进行处理,例如接收到一个持续响应的串流(stream),像是模拟伺服端推播的时候。)

onreadystatechange的第一个参数会是Event实例,其target特性会是XMLHttpRequest实例,可以使用statusText获取响应状态码代表的文本消息,而XMLHttpRequestresponseText获取伺服端的响应文本,不过要注意,伺服端响应时若没有指明字符集(例如Content-Type: text/html; charset=UTF-8之类),responseText默认会使用 UTF-8 字符集来解读返回的文本。

如果响应是 XML,可以使用responseXML获取解析后的 XML DOM 对象。

以下是一个非同步获取数据的完整流程示范,其中请求的纯文件中包括中文,所以先存储为 UTF-8 格式:

<table style="text-align: left; width: 100%;" border="1" cellpadding="2" cellspacing="2">
<tbody>
    <tr>
        <td style="vertical-align: top;">标题一</td>
        <td style="vertical-align: top;">标题二</td>
        <td style="vertical-align: top;">标题三</td>
        <td style="vertical-align: top;">标题四</td>
    </tr>
    <tr>
        <td style="vertical-align: top;">数据1</td>
        <td style="vertical-align: top;">数据3</td>
        <td style="vertical-align: top;">数据5</td>
        <td style="vertical-align: top;">数据7</td>
    </tr>
    <tr>
        <td style="vertical-align: top;">数据2</td>
        <td style="vertical-align: top;">数据4</td>
        <td style="vertical-align: top;">数据6</td>
        <td style="vertical-align: top;">数据8</td>
    </tr>
</tbody>
</table>

执行的结果是以非同步方式获取文件,并在同一个页面显示内容:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
</head>
<body>

    <button id='req'>获取表格</button>
    <div id="table"></div>

<script type="text/javascript">

    document.getElementById('req').onclick = function() {
        let request = new XMLHttpRequest();
        request.onreadystatechange = function(evt) {
            let req = evt.target;
            if(req.readyState === XMLHttpRequest.DONE && req.status === 200) {
                document.getElementById('table').innerHTML = req.responseText;
            }
        };
        request.open('GET', 'XMLHttpRequest-1.txt');
        request.send(null);
    };

</script>   

</body>
</html>

按我观看执行结果


展开阅读全文