本章內(nèi)容
- 使用
XMLHttpRequest對(duì)象 - 使用
XMLHttpRequest事件 - 跨域 Ajax 通信的限制
Ajax 技術(shù)的核心是 XMLHttpRequest對(duì)象(簡(jiǎn)稱 XHR)。
21.1 XMLHttpRequest 對(duì)象
var xhr = new XMLHttpRequest();
21.1.1 XHR 的用法
在使用 XHR 對(duì)象時(shí),要調(diào)用的第一個(gè)方法是open(),以啟動(dòng)一個(gè)請(qǐng)求以備發(fā)送,它接受 3 個(gè)參數(shù):要發(fā)送的請(qǐng)求類型,請(qǐng)求的 URL 和表示是否異步發(fā)送請(qǐng)求的布爾值。
xhr.open("get", "example.php", false);
只能向同一個(gè)域中使用相同端口和協(xié)議的 URL 發(fā)送請(qǐng)求。如果 URL 與啟動(dòng)請(qǐng)求的頁面有任何差別,都會(huì)引發(fā)安全錯(cuò)誤。
要發(fā)送特定的請(qǐng)求,必須像下面這樣調(diào)用send()方法:
xhr.open("get", "example.txt", false);
xhr.send(null);
這里的send()方法接收一個(gè)參數(shù),即要作為請(qǐng)求主體發(fā)送的數(shù)據(jù)。如果不需要通過請(qǐng)求主體發(fā)送數(shù)據(jù),則必須傳入null,因?yàn)檫@個(gè)參數(shù)對(duì)有些瀏覽器來說是必需的。調(diào)用send()后,請(qǐng)求就會(huì)被分派到服務(wù)器。
在收到響應(yīng)后,響應(yīng)的數(shù)據(jù)會(huì)自動(dòng)填充 XHR 對(duì)象的屬性,相關(guān)的屬性簡(jiǎn)介如下。
-
responseText:作為響應(yīng)主體被返回的文本 -
responseXML:如果響應(yīng)的內(nèi)容類型是"text/xml"或"application/xml",這個(gè)屬性中將保存包含著響應(yīng)數(shù)據(jù)的 XML DOM 文檔。 -
status:響應(yīng)的 HTTP 狀態(tài)。 -
statusText:HTTP 狀態(tài)的說明。
為確保接收適當(dāng)?shù)捻憫?yīng),應(yīng)該像下面這樣檢查上述這兩種狀態(tài)代碼:
xhr.open("get", "example.txt", false);
xhr.send(null);
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("request was unsuccessful:" + xhr.status);
}
多數(shù)情況下,需要發(fā)送異步請(qǐng)求,才能讓 JavaScript 繼續(xù)執(zhí)行而不必等待響應(yīng)。此時(shí),可以檢測(cè) XHR 對(duì)象的readyState屬性,該屬性表示請(qǐng)求/響應(yīng)過程的當(dāng)前活動(dòng)階段。這個(gè)屬性可取的值如下。
- 0:未初始化。尚未調(diào)用
open()方法。 - 1:?jiǎn)?dòng)。已經(jīng)調(diào)用
open()方法,但尚未調(diào)用send()方法。 - 2:發(fā)送。已經(jīng)調(diào)用
send()方法,但尚未接收到響應(yīng)。 - 3:接收。已經(jīng)接收到部分響應(yīng)數(shù)據(jù)。
- 4:完成。已經(jīng)接收到全部響應(yīng)數(shù)據(jù),而且已經(jīng)可以在客戶端使用了。
readyState屬性值變化時(shí),會(huì)觸發(fā)readystatechange事件
。通常,我們只對(duì)readyState值為 4 的階段感興趣,因?yàn)檫@時(shí)所有數(shù)據(jù)都已經(jīng)就緒。
var xhr = createXHR();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ((xhr.state >= 200 && xhr.state.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "example.txt", true);
xhr.send(null);
另外,在接收到響應(yīng)之前還可以調(diào)用abort()方法來取消異步請(qǐng)求。
xhr.abort();
21.1.2 HTTP 頭部信息
每個(gè) HTTP 請(qǐng)求和響應(yīng)都會(huì)帶有相應(yīng)的頭部信息,其中有的對(duì)開發(fā)人員有用,有的也沒有什么用。
XHR對(duì)象提供了操作這兩種頭部信息的方法。
默認(rèn)情況下,在發(fā)送XHR請(qǐng)求的同時(shí),還會(huì)發(fā)送下列頭部信息(略)。
使用setRequestHeader()方法可以設(shè)置自定義的請(qǐng)求頭部信息。必須在調(diào)用open()方法之后且調(diào)用send()方法之前調(diào)用setRequestHeader()。
調(diào)用XHR對(duì)象的getResponseHeader()方法并傳入頭部字段名稱,可以取得相應(yīng)的響應(yīng)頭部信息。
21.1.3 GET 請(qǐng)求
查詢字符串中每個(gè)參數(shù)的名稱和值都必須使用encodeURIComponent()進(jìn)行編碼,然后才能放到 URL 的末尾;而且所有名-值對(duì)都必須由和號(hào)分隔。
下面這個(gè)函數(shù)可以輔助向現(xiàn)有 URL 的末尾添加查詢字符串參數(shù):
function addURLParam(url, name, value) {
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
21.2.4 POST 請(qǐng)求
21.2 XMLHttpRequest 2 級(jí)
21.2.1 FormData
21.2.2 超時(shí)設(shè)定
21.2.3 overrideMimeType() 方法
21.3 進(jìn)度事件
21.3.1 load 事件
21.3.2 progress 事件
21.4 跨源資源共享
21.4.1 IE 對(duì) CORS 的實(shí)現(xiàn)
21.4.2 其他瀏覽器對(duì) CORS 的實(shí)現(xiàn)
使用標(biāo)準(zhǔn)的 XHR 對(duì)象并在open()方法中傳入絕對(duì) URL 即可。
跨域 XHR 對(duì)象也有一些限制。
- 不能使用
setRequestHeader()設(shè)置自定義頭部。 - 不能發(fā)送和接收 cookie。
- 調(diào)用
getAllResponseHeaders()方法總會(huì)返回空字符串。
21.4.3 Preflighted Requests
21.4.4 帶憑據(jù)的請(qǐng)求
21.4.5 跨瀏覽器的 CORS
21.5 其他跨域技術(shù)
21.5.1 圖像 Ping
21.5.2 JSONP
21.5.3 Comet
Comet 是一種更高級(jí)的 Ajax 技術(shù)(“服務(wù)器推送”)。Comet 則是一種服務(wù)器向頁面推送數(shù)據(jù)的技術(shù)。能夠讓信息幾乎實(shí)時(shí)地被推送到頁面上,非常適合處理體育比賽的分?jǐn)?shù)和股票報(bào)價(jià)。
有兩種實(shí)現(xiàn) Comet 的方式:長(zhǎng)輪詢和流。長(zhǎng)輪詢是傳統(tǒng)輪詢的一個(gè)翻版,即瀏覽器定時(shí)向服務(wù)器發(fā)送請(qǐng)求,看有沒有更新的數(shù)據(jù)。
長(zhǎng)輪詢把短輪詢顛倒了一下。頁面發(fā)起一個(gè)服務(wù)器的請(qǐng)求,然后服務(wù)器一直保持連接打開,直到有數(shù)據(jù)可發(fā)送。發(fā)送完數(shù)據(jù)之后,瀏覽器關(guān)閉連接,隨即又發(fā)起一個(gè)到服務(wù)器的新請(qǐng)求。這一過程在頁面打開期間一直持續(xù)不斷。
輪詢的優(yōu)勢(shì)是所有瀏覽器都支持,因?yàn)槭褂?XHR 對(duì)象和setTimeout()就能實(shí)現(xiàn)。而你要做的就是決定什么時(shí)候發(fā)送請(qǐng)求。
第二種是 HTTP 流。它在頁面的整個(gè)生命周期內(nèi)只使用一個(gè) HTTP 連接。具體來說,就是瀏覽器向服務(wù)器發(fā)送一個(gè)請(qǐng)求,就是瀏覽器向服務(wù)器發(fā)送一個(gè)請(qǐng)求,而服務(wù)器保持連接打開,然后周期性地向?yàn)g覽器發(fā)送數(shù)據(jù)。
所有服務(wù)器端語言都支持打印到輸出緩存然后刷新(將輸出緩存中的內(nèi)容一次性全部發(fā)送到客戶端)的功能。而這正是實(shí)現(xiàn) HTTP 流的關(guān)鍵所在。
通過偵聽readystatechange事件及檢測(cè)readyState的值是否為 3,就可以利用 XHR 對(duì)象實(shí)現(xiàn) HTTP 流。
21.5.4 服務(wù)器發(fā)送事件
SSE(Server-Sent Events, 服務(wù)器發(fā)送事件)是圍繞只讀 Comet 交互推出的 API 或者模式。SSE API 用于創(chuàng)建到服務(wù)器的單向連接,服務(wù)器通過這個(gè)連接可以發(fā)送任意數(shù)量的數(shù)據(jù)。
21.5.5 Web Sockets
目標(biāo)是在一個(gè)單獨(dú)的持久連接上提供全雙工、雙向通信。
21.5.6 SSE 與 Web Sockets
21.6 安全
為確保通過 XHR 訪問的 URL 安全,通行的做法就是驗(yàn)證發(fā)送請(qǐng)求者是否有權(quán)限訪問相應(yīng)的資源。
有下列幾種方式可供選擇
- 要求以 SSL 連接來訪問可以通過 XHR 請(qǐng)求的資源。
- 要求每一次請(qǐng)求都要附帶經(jīng)過相應(yīng)算法計(jì)算得到的驗(yàn)證碼。
21.7 小結(jié)
Ajax 是無需刷新頁面就能夠從服務(wù)器取得數(shù)據(jù)的一種方法。