跳转到内容

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 = 打开 -send()尚未被调用。
  • 2 = 已发送 -send()已被调用,标头和状态可用。
  • 3 = 正在接收 - 正在下载,responseText包含部分数据
  • 4 = 已加载 - 完成。
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 在每次刷新页面时都会重新验证缓存的响应,并使用“Last-Modified”标头的值作为“If-Modified-Since”标头的值,该标头包含在缓存的响应中。

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 对象。

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

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

如果脚本执行具有副作用的操作(例如,添加评论、将消息标记为已读),这些操作需要请求始终到达最终服务器,则应使用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 方法中隐式地重置了对象,如果状态为 'completed'。 有关重用的更多解释:在 IE 中重用 XMLHttpRequest 对象。 在设置回调函数后调用 open 方法的缺点是会失去对 readystates 的跨浏览器支持。 请参见quirksmode 文章。

进一步阅读

[编辑 | 编辑源代码]


华夏公益教科书