JavaScript/XMLHttpRequest

这是对XMLHttpRequest对象的指南和参考,是Ajax编程中要了解的关键组件。

示例 编辑

下面是一个使用XMLHttpRequest的网页的简短示例。 我们将详细介绍解决以后可能出错的各种问题的方法。

<html><!-- example.html : public domain -->
<script language="JavaScript" type="text/JavaScript" >
function alertContents(httpRequest) {
  if (httpRequest.readyState == 4) {
    // Everything is good, the response is received
    if ((httpRequest.status == 200) || (httpRequest.status == 0)) {
      // FIXME: perhaps a better example is to *replace* some text in the page.
      var htmlDoc = document.createElement('div'); // Create a new, empty DIV node.
      htmlDoc.innerHTML = httpRequest.responseText; // Place the returned HTML page inside the new node.
      alert("The response was: " + httpRequest.status + httpRequest.responseText);
    } else {
      alert('There was a problem with the request. ' + httpRequest.status + httpRequest.responseText);
    }
  }
}

function send_with_ajax(the_url) {
  var httpRequest = new XMLHttpRequest();
  httpRequest.onreadystatechange = function() { alertContents(httpRequest); };
  httpRequest.open("GET", the_url, true);
  httpRequest.send(null);
}
</script>

<p onClick="send_with_ajax('example.html');">
Click me!
</p>
</html>

对象参考 编辑

方法 编辑

abort()
取消当前请求.
getAllResponseHeaders()
以字符串形式返回完整的 HTTP 标头集
getResponseHeader(headerName)
返回指定 HTTP 标头的值.
open(method, URL)
open(method, URL, async)
open(method, URL, async, userName)
open(method, URL, async, userName, password)
指定请求的方法、URL 和其他可选属性.
  • method参数的值可以是GET, POST, HEAD, PUT, DELETE或W3C规范中列出的各种其他HTTP方法
  • URL参数可以是相对 URL,也可以是完整 URL.
  • async参数指定是否应该异步处理请求 - true表示脚本处理在send()方法之后继续,不等待响应,false表示脚本在继续脚本处理之前等待响应.
send(content)
发送请求。content可以是字符串或对文档的引用.
setRequestHeader(label, value)
label/value对添加到要发送的 HTTP 标头.

属性 编辑

onreadystatechange
为在每次状态更改时触发的事件指定对事件处理程序的引用
readyState
返回对象的状态如下:
  • 0 = 未初始化 – open() 尚未被调用。
  • 1 = open – send() 尚未被调用。
  • 2 = sent – send() 已被调用,标题和状态可用。
  • 3 = receiving – 正在下载,responseText 保存部分数据
  • 4 = loaded – 完成。
responseText
以字符串形式返回响应.
responseXML
以 XML 格式返回响应。此属性返回一个 XML 文档对象,可以使用 W3C DOM 节点树方法和属性对其进行检查和解析.
responseBody
以二进制编码字符串的形式返回响应。此属性不是本机 XMLHttpRequest 包装器的一部分。要使该属性可用,必须使用 ActiveX 组件创建 XHR 对象。一个 JScript 示例:
if (typeof ActiveXObject !== "undefined") {
  xmlhttp = new ActiveXObject("MSXML2.XMLHTTP");
  xmlhttp.open("GET", "#", false);
  xmlhttp.send(null);
  alert(xmlhttp.responseBody);
} else {
  alert("This browser does not support Microsoft ActiveXObjects.")
}
status
以数字形式返回 HTTP 状态代码(例如,404 表示“未找到”,200 表示“正常”)。如果访问状态字段,某些与网络相关的状态代码(例如“请求超时”的 408)会导致在 Firefox 中抛出错误。如果服务器没有(正确地)响应,IE 会返回一个 WinInet 错误代码(例如 12029 表示“无法连接”).
statusText
以字符串形式返回状态(例如“未找到”或“确定”).

错误和不一致 编辑

处理 XMLHttpRequest 实现中的错误和不一致:

缓存 编辑

大多数实现还实现了 HTTP 缓存。 Internet Explorer 和 Firefox就是如此,但在重新验证缓存数据的方式和时间方面存在差异。

Firefox 每次刷新页面时都会重新验证缓存的响应,发出一个“If-Modified-Since”标头,其值设置为缓存响应的“Last-Modified”标头的值。

Internet Explorer 仅在缓存响应过期时(即,在收到“Expires”标头的日期之后)才会这样做。 这引发了一些问题,因为 Internet Explorer 中存在一个错误,其中缓存的响应永远不会刷新。

可以统一客户端上的缓存行为。 以下脚本说明了一个示例方法:

var request = new XMLHttpRequest();
request.open("GET", url, false);
request.send(null);
if (!request.getResponseHeader("Date")) {
  var cached = request;
  request = new XMLHttpRequest();
  var ifModifiedSince =
  cached.getResponseHeader("Last-Modified") ||
  new Date(0); // January 1, 1970
  request.open("GET", url, false);
  request.setRequestHeader("If-Modified-Since", ifModifiedSince);
  request.send("");
  if (request.status == 304) {
    request = cached;
  }
}

在 Internet Explorer 中,如果响应从缓存中返回而没有重新验证,则“Date”标头是一个空字符串。解决方法是通过检查“Date”响应标头并在需要时发出另一个请求来实现。如果需要第二次请求,则不会发出两次实际的 HTTP 请求,因为第一次调用不会产生实际的 HTTP 请求。

缓存请求的引用被保留,因为如果第二次调用的响应码/状态是“304 Not Modified”,响应体变成空字符串(“”),然后需要返回缓存对象.节省内存和创建第二个对象的费用的一种方法是仅保留所需的响应数据并重用 XMLHttpRequest 对象。

上面的脚本依赖于“日期”标头始终由服务器发出的假设,这对于大多数服务器配置应该是正确的。此外,它还说明了服务器和客户端之间的同步通信。在异步通信的情况下,应在回调期间进行检查。

这个问题通常可以通过采用完全阻止缓存的技术来克服。不加选择地使用这些技术会导致性能下降和网络带宽浪费。

如果脚本执行具有副作用的操作(例如,添加评论、将消息标记为已读)要求该请求始终到达最终服务器,则应使用 POST 方法。

解决方法 编辑

Internet Explorer 也会缓存动态页面,这是一个问题,因为页面的 URL 可能不会更改,但内容会更改(例如新闻提要)。 这种情况的解决方法可以通过添加唯一的时间戳或随机数来实现,或者可能两者都添加,通常使用 Date 对象和/或 Math.random()。

对于简单的文档请求,查询字符串分隔符“?” 可以使用,或者对于现有查询,可以在最终的“&”之后添加最终的子查询——将唯一的查询词附加到现有的查询中。 缺点是每个这样的请求都会用无用(从未重用)的内容填充缓存,否则这些内容可以用于其他缓存的内容(更多有用的数据将从缓存中清除,以便为这些一次性响应腾出空间)。

通过向动态页面添加元标记以使其不可缓存,可以实现更好的解决方法:

<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="-1" />

在 IE 中重用 XMLHttpRequest 对象 编辑

在 IE 中,如果在设置 onreadystatechange 回调后调用 open 方法,尝试重用 XHR 对象时会出现问题。为了能够正确地重用 XHR 对象,请先使用 open 方法,然后再设置 onreadystatechange。 发生这种情况是因为如果状态为“已完成”,IE 会在 open 方法中隐式重置对象。 有关重用的更多说明:Reusing XMLHttpRequest Object in IE。 在设置回调后调用 open 方法的缺点是失去了对就绪状态的跨浏览器支持。 请参阅the quirksmode article.

链接 编辑

进一步阅读 编辑