利用原生js封裝一個ajax api(一)
此係列文章主要分享一下如何利用原生js,自己封裝一個ajax api。本篇文章先來為此做一些前提準備,瞭解一下ajax請求少不了的XMLHttpRequest類。
瀏覽器在XMLHttpRequest類上定義了他們的HTTP API。 這個類的每一個例項都是一個獨立的請求/響應對,這個物件的屬性和方法允許指定請求細節和提取響應資料。
一、例項化XMLHttpResquest()
使用這個HTTP API的第一步就是例項化一個XMLHttpRequest物件:
var requestObj new XMLHttpRequest();
當然,實際開發中,不會這麼簡單,我們還要考慮相容早版本的IE的問題,在IE5和IE6中它只是一個ActiveX物件。IE7之前的版本不支援非標準化的XMLHttpRequest()建構函式。我們需要這樣寫:
if (window.XMLHttpRequest) {
requestObj = new XMLHttpRequest();
} else {
requestObj = new ActiveXObject("Microsoft.XMLHTTP")//相容早版本的ie, 如IE5 IE6
}
除了例項化一個XMLHttpRequest物件,我們也可以重用已有的物件,但要注意,這樣會終止之前通過該物件掛起的任何請求。
請求和響應的組成
一個http請求由4部分組成:
- 方法或“動作”
- 請求的 url
- 可選的請求頭集合,可能包含身份驗證資訊
- 可選的請求主體
HTTP響應包含3部分:
- 狀態碼,顯示請求的狀態,如是否成功
- 響應頭集合
- 響應主體
二、指定請求
發起HTTP請求的下一步是呼叫XMLHttpRequest物件的open()方法:
request.open("方法", "URL")
open()方法需要指定兩個必要部分:方法 和 url。第一個引數為“方法”,不區分大小寫,但通常使用大寫,常用的方法有 “GET”“POST”。GET 方法用於常規請求,它適用於當URL完全指定請求資源,請求對伺服器沒有任何副作用以及伺服器響應是可快取的。POST方法常用於HTML表單,它在請求主體中包含額外資料,且這些資料常需要儲存到伺服器的資料庫上(副作用)。不同的額外資料伺服器可能返回不同的資料。
除了POST和GET方法,還有“DELETE”“HEAD”“OPTION” “PUT”等方法。他們都可以作為open()方法的第一個引數。
open()方法還有第三個引數,用來指定方法是同步還是非同步的。而預設是非同步的,這個在文章後面會細講。
三、設定請求頭
如果有請求頭的話,我們可以通過
requestObj.setRequestHeader("Content-Type", " ")
來設定請求頭。
要注意的是:對相同的頭呼叫setRequestHeader()多次,新值不會取代舊值,相反,HTTP請求將包含這個頭的多個副本或這個頭將指定多個值。並不是所有的頭都可以設定,如“Content-length””Date” “Referer” 和 “User-Agent”等,XMLHttpRequest將自動新增這些頭而防止偽造它們。
四、傳送請求
使用XMLHttpRequest的最後一步是指定可選的請求主體並向伺服器傳送它。使用send()方法:
requestObj.send(null)
GET方法沒有主體,我們在send()方法中傳入null或省略這個引數。POST請求通常擁有主體,同時應該配合setRequestHeader()指定的“Content-Type”頭。
到現在,我們可以看到一個完整的傳送請求的過程:
var requestObj;
if (window.XMLHttpRequest) {
requestObj = new XMLHttpRequest();
} else {
requestObj = new ActiveXObject("Microsoft.XMLHTTP")
}
requestObj.open("方法", url, async);
requestObj.setRequestHeader("Content-Type", "xxxxxxxx") //根據方法設定相應的頭
requestObj.send();
前面部分講了如何 傳送ajax請求,下面部分是如何 取得響應
五、取得響應
一個完整的HTTP響應由狀態碼、響應頭集合和響應主體組成。這些都可以通過XMLHttpRequest物件的屬性和方法使用。
- status和statusText屬性以數字和文字的形式返回HTTP狀態碼。
- getResponseHeader()和getAllResponseHeaders()能查詢響應頭。
- 響應主體可以從 reponseText 屬性中得到文字形式,從responseXML中得到Document形式。
在send()方法傳送後,我們需要知道我們的請求什麼時候得到了響應,請求是否成功等,這時候我們就要用到XMLHttpResquest物件上的 readyState 屬性,readyState屬性是一個整數,它指定了請求的狀態:
常量 | 值 | 含義 |
---|---|---|
UNSENT | 0 | open()尚未使用 |
OPENED | 1 | open()已呼叫 |
HEADERS_RECEIVED | 2 | 接收到頭部資訊 |
LOADING | 3 | 接收到響應主體 |
DONE | 4 | 響應完成 |
通過readyState我們就可以知道當前的請求出於什麼狀態了,那我們怎麼去監聽readyState呢?其實在每次readyState改變的時候,都會觸發readystatechange事件,而我們可以通過onreadystatechange屬性去監聽readystatechange事件。所以通過onreadystatechange屬性就可以間接的監聽到readyState的改變了。當然我們也可以使用addEventListener()方法來監聽,但我們通常不這麼做。
所以我們可以通過下面程式碼來獲取響應資訊:
requestObj.onreadystatechange = function() { // 監聽readyState的變化
if (requestObj.readyState == 4) { // 判斷響應是否完成
if (requestObj.status == 200) { // 判斷請求是否成功
console.log(resquestObj.responseText);
}
}
}
所以到這裡,我們應該知道了一個完整的原生ajax請求是怎麼樣的了。
// 例項化XMLHttpRequest
var requestObj;
if (window.XMLHttpResquest) {
requestObj = new XMLHttpRequest();
} else {
requestObj = new ActiveXObject("Microsoft.XMLHTTP")
}
// 傳送請求
requestObj.open("TYPE", "URL");
requestObj.setRequestHeader("Content-Type", .....);
requestObj.send();
// 獲取響應
requestObj.onreadystatechange = function() {
if (requestObj.readyState == 4) {
if (requestObj.status == 200) {
console.log(requestObj.reponseText);
}
}
}
六、同步請求
是否還記得前面說到,open()方法還有第三個引數,它指定請求是同步的還是非同步的,而預設值為true, 使得請求為非同步請求。我們可以給它傳入false來實現同步請求。
requestObj.open(type, url, false);
這樣我們就不需要去監聽readyState的值來獲知請求何時得到了響應了。
requestObj.open("TYPE", "URL", false);
requestObj.setRequestHeader("Content-Type", .....);
requestObj.send();
// 當請求得到響應才執行
if (requestObj.status != 200) throw new Error(request.statusText);
console.log(requestObj.reponseText);
同步請求是吸引人的,但是同步請求意味著什麼呢?意味著由於JavaScript是單執行緒的,當send()方法呼叫後,請求發出,send()方法將阻塞這份程式碼,send()方法後面的程式碼都不會被執行,直到請求得到響應,如果連線的伺服器響應慢,使用者的瀏覽器UI就會被凍結。所以不是特殊情況,最好不用同步請求。