JS XMLHttpRequest 2.0版本新特性

2020-07-16 10:05:11
XMLHttpRequest 1.0 只是把已有的 XMLHttpRequest 物件的實現細節描述出來,而 XMLHttpRequest 2.0 則進一步發展了 XMLHttpRequest;並非所有瀏覽器都完整實現了 XMLHttpRequest 2.0 規範,但是所有瀏覽器都實現了 XMLHttpRequest 2.0 規定的部分內容。

認識 XMLHttpRequest 2.0

XMLHttpRequest 1.0 API 存在以下缺陷。
  • 只支援文字資料的傳送,無法用來讀取和上傳二進位制檔案。
  • 傳送和接收資料時,沒有進度資訊,只能提示有沒有完成。
  • 受到同域限制,只能向同一域名的伺服器請求資料。

2014 年 11 月 W3C 正式發布 XMLHttpRequest Level 2(http://www.w3.org/TR/XMLHttpRequest2/)標準規範,新增了很多實用功能,推動非同步互動在 JavaScript 中的應用。說明如下:
  • 可以設定 HTTP 請求的時限。
  • 可以使用 FormData 物件管理表單資料。
  • 可以上傳檔案。
  • 可以請求不同域名下的資料(跨域請求)。
  • 可以獲取伺服器端的二進位制資料。
  • 可以獲得資料傳輸的進度資訊。

請求時限

XMLHttpRequest 2.0 為 XMLHttpRequest 物件新增 timeout 屬性,使用該屬性可以設定 HTTP 請求時限。
xhr.timeout = 3000;
上面語句將非同步請求的最長等待時間設為 3000 毫秒。超過時限,就自動停止 HTTP 請求。

與之配套的還有一個 timeout 事件,用來指定回撥函數。
xhr.ontimeout = function (event) {
    console.log('請求超時!');
}

FormData 資料物件

在 JavaScript 中,XMLHttpRequest 2.0 新增 FormData 物件,使用它可以處理表單資料。

操作步驟

1) 新建 FormData 物件。
var formData = new FormData();

2) 為 FormData 物件新增表單項。
form.append('user', '張三');
form.append('pass', '123456');

3) 直接傳送 FormData 物件。
xhr.send(formData);

4) FormData 物件也可以直接獲取網頁表單的值。
var form = document.getElementById('myform');
var formData = new FormData(form);
formData.append('grade', '2');  //新增一個表單項
xhr.open('POST', 'form.action');
xhr.send(formData);

上傳檔案

新版 XMLHttpRequest 物件不僅可以傳送文字資訊,還可以上傳檔案。使用 send() 方法可以傳送字串、Document 物件、表單資料、Blob 物件、檔案和 ArrayBuffer 物件。

範例

設計一個“選擇檔案”的表單元素(input[type="file"]),並將它裝入 FormData 物件。
var formData = new FormData();
for (var i = 0; i < files.length; i ++){
    formData.append('files[]', files[i]);
}
然後,傳送 FormData 物件給伺服器。
xhr.send(formData);

跨域存取

XMLHttpRequest 2.0 版本允許向不同域名的伺服器發出 HTTP 請求。使用跨域資源共用的前提是:瀏覽器必須支援這個功能,且伺服器端必須同意這種跨域。如果能同時滿足上面兩個條件,則程式碼的寫法與不跨域的請求完全一樣。例如:
var xhr = createXHR();
var url = 'http://other.server/and/path/to/script';  //請求的跨域檔案
xhr.open('GET', url, true);
xhr.onreadystatechange = function () {
    if (xhr.readyState == 4 && xhr.status == 200) {
        console.log(xhr.responseText);
    }
}
xhr.send();

應用不同型別資料

新版本的 XMLHttpRequest 物件新增 responseType 和 response 屬性。
  • responseType:用於指定伺服器端返回資料的資料型別,可用值為 text、arraybuffer、blob、json 或 document。如果將屬性值指定為空字串值或不使用該屬性,則返回響應的資料。
  • response:如果向伺服器端提交請求成功,則返回響應的資料。
  • 如果 responseType 為 text,則 response 返回值為一串字串。
  • 如果 responseType 為 arraybuffer,則 response 返回值為一個 ArrayBuffer 物件。
  • 如果 responseType 為 blob,則 response 返回值為一個 Blob 物件。
  • 如果 responseType 為 json,則 response 返回值為一個 JSON 物件。
  • 如果 responseType 為 document,則 response 返回值為一個 Document 物件。

接收二進位制資料

XMLHttpRequest 1.0 版本只能從伺服器接收文字資料,而 XMLHttpRequest 2.0版本則可以接收二進位制資料。使用新增的 responseType 屬性,可以從伺服器接收二進位制資料。

可以把 responseType 設為 blob,表示伺服器傳回的是二進位制物件。
var xhr = new XMLHttpRequest ();
xhr.open('GET', '/path/to/image.png');
xhr.responseType = 'blob';
接收資料的時候,用瀏覽器自帶的 Blob 物件即可。
var blob = new Blob ([xhr.response], {type : 'image/png'});
是讀取 xhr.response,而不是 xhr.responseText。

可以將 responseType 設為 arraybuffer,把二進位制資料裝在一個陣列裡。
var xhr = new XMLHttpRequest ();
xhr.open('GET', '/path/to/image.png');
xhr.responseType = 'arraybuffer';
接收資料的時候,需要遍歷這個陣列。
var arrayBuffer = xhr.response;
if (arrayBuffer) {
    var byteArray = new Unit8Array (arrayBuffer);
    for (var i = 0; i < byteArray.byteLength; i ++ ) {
        //執行程式碼
    }
}

監測資料傳輸進度

新版本的 XMLHttpRequest 物件新增了一個 progress 事件,用來返回進度資訊。它分成上傳和下載兩種情況。下載的 progress 事件屬於 XMLHttpRequest 物件,上傳的 progress 事件屬於 XMLHttpRequest.upload 物件。

操作步驟

1) 先定義 progress 事件的回撥函數。
xhr.onprogress = updateProgress;
xhr.upload.onprogress = updateProgress;

2) 在回撥函數裡面,使用這個事件的一些屬性。
function updateProgress (event) {
    if (event.lengthComputable) {
        var percentComplete = event.loaded / event.total;
    }
}
上面程式碼中,event.total 是需要傳輸的總位元組,event.loaded 是已經傳輸的位元組。如果 event.lengthComputable 不為真,則 event.total 等於 0。

與 progress 事件相關的,還有其他 5 個事件,可以分別指定回撥函數。
  • load:傳輸成功完成。
  • abort:傳輸被使用者取消。
  • error:傳輸中出現錯誤。
  • loadstart:傳輸開始。
  • loadEnd:傳輸結束,但是不知道成功還是失敗。