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.

連結[編輯]

進一步閱讀[編輯]