Ajax 處理服務(wù)端響應(yīng)
在瀏覽器發(fā)送 Ajax 請求之后,下一步驟自然是服務(wù)器響應(yīng)。服務(wù)器在接收到請求之后會進(jìn)行一系列處理步驟,最終返回結(jié)果。而與此同時,客戶端會在接收到返回的結(jié)果之后進(jìn)行界面的展示或者數(shù)據(jù)的處理。
本章節(jié)主講 Ajax 收到返回數(shù)據(jù)后處理服務(wù)器響應(yīng)過程。
前言
本章節(jié)將會從兩個方面來講解 Ajax 如何處理服務(wù)端響應(yīng),它們分別是:
- 處理的時機(jī)
- 處理的方法
如果你不知道 Ajax 是如何獲取服務(wù)端響應(yīng)內(nèi)容的,或者你對 HTTP 狀態(tài)碼沒有一個初步的了解,甚至你還不知道一個 Ajax 請求過程中各個階段的狀態(tài)表示,那么,我相信這個章節(jié)會很適合你。接下來讓我們步入正題,一起來看看 Ajax 是如何處理服務(wù)端響應(yīng)的。
1. 何時處理響應(yīng)
首先思考一個問題,我們應(yīng)該在什么時機(jī)處理服務(wù)端的響應(yīng)呢?
我們知道,Ajax 可以發(fā)送異步請求,那數(shù)據(jù)的返回當(dāng)然也不可能是同步返回的??蛻舳酥挥械鹊椒?wù)端數(shù)據(jù)返回才能進(jìn)行數(shù)據(jù)的下一步處理。如果服務(wù)端沒有正確響應(yīng),或者說服務(wù)端的響應(yīng)還沒結(jié)束,那么客戶端是無法獲得正確響應(yīng)的。講得俏皮一點(diǎn),客戶端在這個時候還得看服務(wù)端的臉色。
那么,在代碼中我們要在什么樣的時機(jī)開始處理響應(yīng)呢?
這里,我們有必要了解一下 XMLHttpRequest.readyState
和 XMLHttpRequest.status
。
1.1 XMLHttpRequest.readyState
在客戶端與服務(wù)器的通信過程中,XMLHttpRequest.readyState 體現(xiàn)著當(dāng)前請求以及服務(wù)端響應(yīng)的狀態(tài)。當(dāng) xhr.readyState == 4
的時候,代表著服務(wù)器響應(yīng)完成。
其他的 readyState 狀態(tài)碼還有 0 、1、2、3,他們分別代表著:
0:狀態(tài)為 UNSENT。表示創(chuàng)建了但還沒有調(diào)用 open 方法。
1:狀態(tài)為 OPENED。表示已經(jīng)調(diào)用了 open 方法。
2:狀態(tài)為 HEADERS_RECEIVED。表示已經(jīng)調(diào)用了 send 方法,且頭部和狀態(tài)也可獲得。
3:狀態(tài)為 LOADING。表示正在下載中。
4:狀態(tài)為 DONE。表示響應(yīng)已經(jīng)完成。
從 readyState 的狀態(tài)碼來看,總共有 5 個狀態(tài)。并且只有最后一個狀態(tài) 4 才能代表著可以開始處理服務(wù)端響應(yīng)數(shù)據(jù)的時機(jī)。
1.2 XMLHttpRequest.status
服務(wù)器響應(yīng)完成之后,我們通常會使用 XMLHttpRequest.status 來查看當(dāng)前 XMLHttpRequest 響應(yīng)中的數(shù)字狀態(tài)碼。這個數(shù)字狀態(tài)碼是一個無符號短整型狀態(tài)碼,代表著我們的 Ajax 請求的狀態(tài)成功與否。
在 XMLHttpRequest 中, status 碼對應(yīng)著標(biāo)準(zhǔn)的 HTTP 狀態(tài)碼。并且在請求完成前,該值為 0。
HTTP 狀態(tài)碼很多,這里就不做過多的鋪開,具體可以到 HTTP 響應(yīng)代碼 進(jìn)行學(xué)習(xí)和查閱。接下來我們來講幾個常見的狀態(tài)碼。
是的,這也是很常見的兩個狀態(tài)碼。
1.2.1 200 和 304 狀態(tài)碼
在 HTTP 狀態(tài)碼中,200 代表著 HTTP 請求成功,而 304 代表著由于瀏覽器緩存原因,GET 請求命中并返回了緩存中的數(shù)據(jù)。結(jié)合 上面 XMLHttpRequest.readyState , 假設(shè)請求成功,我們的響應(yīng)模塊應(yīng)該如下:
xhr.open("GET", "http://localhost:8080/simple/get?mk=慕課網(wǎng)");
xhr.send();
xhr.onreadystatechange = function() {
// 當(dāng)前 this 為 xhr
if (this.readyState == 4) {
if (this.status === 200 || this.status === 304) {
// code ...
}
}
};
在后端設(shè)置了協(xié)商緩存的情況下,我們來看看效果:
第一次請求資源:
刷新頁面,進(jìn)行第二次請求同樣的資源:
由于瀏覽器的緩存機(jī)制,GET請求有可能會緩存我們的請求內(nèi)容。上面前后兩次請求中,第一次請求的時候獲取新的內(nèi)容,返回的是 200 的狀態(tài)碼;而第二次再進(jìn)行獲取,我們就有可能獲取第二圖的結(jié)果,使用的是本地緩存。因此,在對 Ajax 成功的判斷中,我們不應(yīng)該遺漏 304 狀態(tài)碼的判斷。
1.2.2 404 和 500 狀態(tài)碼
有正確的返回,那當(dāng)然也會有錯誤的返回。打個比方,讓我們來假設(shè)這樣的場景:
- 客戶端發(fā)送一個請求,剛好請求的接口找不到,因?yàn)榉?wù)端并沒有提供。
- 客戶端發(fā)送一個請求,服務(wù)端內(nèi)部發(fā)生錯誤了。
如果遇到這樣的情況,Ajax 當(dāng)然不能坐以待斃——我們總不該不把任何響應(yīng)告訴用戶吧!真實(shí)的情況是,Ajax 會返回我們相應(yīng)的 status ,客戶端根據(jù)該 status 進(jìn)行必要的操作。
首先,我們來請求一個捏造的接口,即服務(wù)端并沒有支持的接口。
html 關(guān)鍵容器:
<div id="container"></div>
JavaScript 腳本關(guān)鍵代碼:
var container = document.getElementById('container')
xhr.onreadystatechange = function() {
// 當(dāng)前 this 為 xhr
if (this.readyState == 4) {
if (this.status === 200 || this.status === 304) {
container.innerHTML = "當(dāng)前狀態(tài)碼為: " + this.status;
} else {
container.innerHTML = "當(dāng)前錯誤狀態(tài)碼為: " + this.status; // 主要看這里,出現(xiàn)非 200 和 304 狀態(tài)會在這邊進(jìn)行顯示
}
}
};
看看運(yùn)行后的效果圖:
404 Not Found,顯而易見,當(dāng)我們在查詢的時候,服務(wù)端找不到對應(yīng)的資源的時候就會返回該狀態(tài)碼,表示你要找的東西沒有,不存在。在我們的實(shí)際工作中,我們經(jīng)常會遇到這樣的錯誤,往往這個時候你就應(yīng)該警惕:
- 是不是你的請求 url 寫錯了?
- 是不是前后端線上資源不同步?比方說后端還沒上線對應(yīng)接口而你已經(jīng)在開始在代碼中請求了。
講完 404 狀態(tài)碼,我們接下來繼續(xù)來看看一個很常見的場景,服務(wù)器內(nèi)部發(fā)生錯誤了?。。〈a沿用上一個示例,接口改為服務(wù)端提供的接口,這次我們會在服務(wù)端假設(shè)發(fā)生錯誤,并返回 500 錯誤。
來看看請求的結(jié)果:
事實(shí)上,500 錯誤碼也是非常常見的,500 Internal Server Error 代表著服務(wù)端錯誤,如果我們在開發(fā)過程中遇到這樣的錯誤,那么,就需要后端的同學(xué)來查找原因了。
除此之外,HTTP 狀態(tài)碼還有很多,每個都有不同的含義,這里也不會做過多的展開,有興趣的同學(xué)可以做一個額外的學(xué)習(xí)查閱。HTTP 協(xié)議中,狀態(tài)碼可以讓我們在請求之后,獲知請求的狀態(tài)??蛻舳艘材軌蛞源俗龀鱿鄳?yīng)的響應(yīng)。
2. 如何獲取響應(yīng)內(nèi)容
要獲取響應(yīng)內(nèi)容,當(dāng)然是 XMLHttpRequest 對象下的幾大法器:responseText 、 responseXML 和 response。其中:
- responseText: 一個 DomString,返回一個純文本的值。 當(dāng)該值為 “” 的時候,表示這個請求還沒有開始
send()
;當(dāng)該值為 null 的時候,表示請求失敗。 - responseXML: 處理 XML 響應(yīng)。返回一個包含請求檢索的 HTML 和 XML 的 Document。 當(dāng)請求還沒有
send()
,或者失敗了,甚至是解析失敗的時候,該值為 null 。當(dāng) responseType 不是 “” 或者 "document"的時候,會報錯。 - response: 返回響應(yīng)正文。返回類型可以有 DOMString、 Blob 、ArrayBuffer 、Document 或 JavaScript Object ,這取決于 responseType。
了解獲取響應(yīng)內(nèi)容的這 3 個屬性,接下來,我們會分別返回 DomString、XML 和 Json 類型數(shù)據(jù)來展示著響應(yīng)內(nèi)容。
核心響應(yīng)代碼:
xhr.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status === 200 || this.status === 304) {
var res = this.response
var resText = this.responseText
var resXml = this.responseXML
console.log(res, resText, resXml) // 分別打印三者
}
}
};
2.1 返回 DomString
服務(wù)端返回內(nèi)容:
‘text’
請求結(jié)果:
Content-type:
可以看到,當(dāng)返回的是一個 DomString 的時候,responseText 和 response 都有值,而 responseXML 因?yàn)榻馕鍪?null。
2.2 返回 XML
服務(wù)端返回內(nèi)容:
<data>Hello World</data>
請求結(jié)果:
Content-type:
這一次我們的 XML 正常解析了,并且在控制臺上可以看到打印出了一個 Document,而 response 和 responseText 分別打印了該 XML 的文本形式。
2.3 返回 Json
服務(wù)端返回內(nèi)容:
{a:1}
請求結(jié)果:
Content-type:
當(dāng)返回的是一個 Json 類型數(shù)據(jù)的時候,response 和 responseText 分別為對應(yīng)的文本值,而 responseXML 因?yàn)榻馕鍪〕闪?null。
以上展示了 Ajax 獲取服務(wù)端響應(yīng)的三種類型的數(shù)據(jù),簡單的展示給大家 XMLHttpRequest 的 response、responseText 和 responseXML 在不同數(shù)據(jù)類型下的表現(xiàn),希望以此能夠加深大家對 XMLHttpRequest 的了解。
3. 小結(jié)
- 處理 Ajax 請求,我們應(yīng)該在適當(dāng)?shù)臅r機(jī)進(jìn)行處理。我們應(yīng)該在
xhr.readyState == 4
,并且xhr.status === 200 || xhr.status === 304
的時候正確獲取響應(yīng)的內(nèi)容; - XMLHttpRequest.readyState 體現(xiàn)著當(dāng)前請求以及服務(wù)端響應(yīng)的狀態(tài);
- XMLHttpRequest.status 即 XMLHttpRequest 響應(yīng)中的數(shù)字狀態(tài)碼。這個數(shù)字狀態(tài)碼是一個無符號短整型狀態(tài)碼,代表著我們的 Ajax 請求的狀態(tài)成功與否;
- HTTP 狀態(tài)碼有很多,包括 404、 500 等,每一個包含著不一樣的含義;
- 獲取服務(wù)器響應(yīng)內(nèi)容,我們可以使用 responseText 、 responseXML 和 response 。其中,responseText 返回一個純文本的值,responseXML 返回一個包含請求檢索的 HTML 和 XML 的 Document,而 response 返回響應(yīng)正文。返回類型可以有 DOMString、 Blob 、ArrayBuffer 、Document 或 JavaScript Object ,這取決于 responseType。