1. 程式人生 > >利用原生js封裝一個ajax api(一)

利用原生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就會被凍結。所以不是特殊情況,最好不用同步請求。