如何使用 XMLHttpRequest (XHR) 發出 HTTP 請求
XMLHttpRequest (XHR) 是微軟在 90 年代初發明的,並在 21 世紀頭十年中期成為異步服務器交互的首選技術。
多虧了 XHR,第一次可以在不重新加載整個頁面的情況下更新網頁的部分內容。
XMLHttpRequest
是所有現代瀏覽器中的內置瀏覽器對象,可用於在 JavaScript 中發出 HTTP 請求,以在 Web 瀏覽器和服務器之間交換數據。
儘管名稱中有“XML”一詞,但 XMLHttpRequest
可用於檢索任何類型的數據,而不僅僅是 XML。我們可以使用它來上傳/下載文件、提交表單數據、跟踪進度等等。
基本 XHR 請求
要使用 XHR 發送 HTTP 請求,請創建一個 XMLHttpRequest
對象,打開到 URL 的連接,然後發送請求。一旦請求完成,該對象將包含有用的信息,例如響應正文和 HTTP 狀態碼。
讓我們使用 JSONPlaceholder 測試 REST API 使用 XHR 發送 GET 請求:
// create an XHR object
const xhr = new XMLHttpRequest();
// listen for `onload` event
xhr.onload = () => {
// process response
if (xhr.status == 200) {
// parse JSON data
console.log(JSON.parse(xhr.response));
} else {
console.error('Error!');
}
};
// create a `GET` request
xhr.open('GET', 'https://jsonplaceholder.typicode.com/users');
// send request
xhr.send();
xhr.open()
方法
在上面的示例中,我們將 HTTP 方法和請求的 URL 傳遞給 open()
方法。此方法通常在 new XMLHttpRequest()
之後立即調用 .我們可以使用這個方法來指定請求的主要參數:
下面是這個方法的語法:
xhr.open(method, URL, [async, user, password])
method
— HTTP 請求方法。可以是GET
,POST
,DELETE
,PUT
等。URL
— 要請求的 URL,字符串或 URL 對象asnyc
— 指定是否應異步發出請求。默認值為true
username
&password
— 基本 HTTP 身份驗證的憑據
open()
方法不會打開到 URL 的連接。它只配置 HTTP 請求。
xhr.send()
方法
xhr.send([body])
send()
方法打開網絡連接並將請求發送到服務器。它需要一個可選的 body
包含請求正文的參數。對於像 GET
這樣的請求方法 不需要傳遞body參數。
XHR 事件
使用最廣泛的三個 XHR 事件如下:
load
— 當結果準備好時調用此事件。相當於xhr.onreadystatechange
xhr.readyState == 4
的事件 .error
— 由於網絡故障或無效 URL 導致請求失敗時觸發此事件。progress
— 此事件在響應下載期間定期觸發。它可用於報告大型網絡請求的進度。
// listen for `load` event
xhr.onload = () => {
console.log(`Data Loaded: ${xhr.status} ${xhr.response}`);
};
// listen for `error` event
xhr.onerror = () => {
console.error('Request failed.');
}
// listen for `progress` event
xhr.onprogress = (event) => {
// event.loaded returns how many bytes are downloaded
// event.total returns the total number of bytes
// event.total is only available if server sends `Content-Length` header
console.log(`Downloaded ${event.loaded} of ${event.total}`);
}
請求超時
您可以通過指定時間(以毫秒為單位)輕鬆配置請求超時:
// set timeout
xhr.timeout = 5000; // 5 seconds
// listen for `timeout` event
xhr.ontimeout = () => console.log('Request timeout.', xhr.responseURL);
響應類型
我們可以使用 xhr.responseType
設置預期響應格式的屬性:
- 空(默認)或
text
— 純文本 json
— 解析的 JSONblob
— 二進制數據 Blobdocument
— XML 文檔arraybuffer
—ArrayBuffer
對於二進制數據
讓我們調用一個 RESTful API 來獲取 JSON 格式的響應:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.jsonbin.io/b/5d5076e01ec3937ed4d05eab/1');
// set response format
xhr.responseType = 'json';
xhr.send();
xhr.onload = () => {
// get JSON response
const user = xhr.response;
// log details
console.log(user.name); // John Doe
console.log(user.email); // [email protected]
console.log(user.website); // http://example.com
}
請求狀態(xhr.readyState
)
XMLHttpRequest
對象隨著請求的進行而改變狀態。我們可以使用 xhr.readyState
訪問當前狀態 屬性。
狀態是:
UNSENT
(0) — 初始狀態OPENED
(1) — 請求開始HEADERS_RECEIVED
(2) — 收到的 HTTP 標頭LOADING
(3) — 響應正在加載DONE
(4) — 請求完成
我們可以使用 onreadystatechange
來跟踪請求狀態 事件:
xhr.onreadystatechange = function () {
if(xhr.readyState == 1) {
console.log('Request started.');
}
if(xhr.readyState == 2) {
console.log('Headers received.');
}
if (xhr.readyState == 3) {
console.log('Data loading..!');
}
if (xhr.readyState == 4) {
console.log('Request ended.');
}
};
中止請求
我們可以隨時通過調用 abort()
輕鬆中止 XHR 請求 xhr
上的方法 對象:
xhr.abort(); // cancel request
同步請求
默認情況下,XHR 發出一個有利於性能的異步請求。但是如果你想發出一個顯式的同步請求,只需傳遞 false
作為 open()
的第三個參數 方法。它將在 send()
處暫停 JavaScript 執行 並在響應可用時恢復:
xhr.open('GET', 'https://api.jsonbin.io/b/5d5076e01ec3937ed4d05eab/1', false);
HTTP 標頭
XMLHttpRequest
允許我們設置請求標頭以及讀取響應標頭。我們可以設置請求Content-Type
&Accept
通過調用 setRequestHeader()
標頭 xhr
上的方法 對象:
// set request headers
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Accept', '*/*'); // accept all
同樣,如果您想讀取響應標頭(Set-Cookie
除外) ),調用 getResponseHeader()
在 xhr
對象:
// read response headers
xhr.getResponseHeader('Content-Type');
xhr.getResponseHeader('Cache-Control');
想要立即獲取響應標頭?使用 getAllResponseHeaders()
而是:
xhr.getAllResponseHeaders();
XHR POST 請求
XMLHttpRequest
提交表單數據的POST請求可以通過兩種方式發送:
- 僅使用 Ajax
- 使用
FormData
API
第一種方法已經足夠好了,除非你想上傳一個文件並且需要 multipart/form-data
編碼。以下是我們如何使用 URL 編碼的表單數據發出 POST 請求:
const xhr = new XMLHttpRequest();
// configure a `POST` request
xhr.open('POST', '/login');
// prepare form data
let params = 'username=attacomsian&password=123456';
// set `Content-Type` header
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// pass `params` to `send()` method
xhr.send(params);
// listen for `load` event
xhr.onload = () => {
console.log(xhr.responseText);
}
想要發出 JSON POST 請求? 確保使用 JSON.stringify() 將 JSON 數據轉換為字符串並設置 Content-Type
application/json
的標頭 :
const xhr = new XMLHttpRequest();
// configure a `POST` request
xhr.open('POST', '/login');
// create a JSON object
const params = {
username: 'attacomsian',
password: '123456'
};
// set `Content-Type` header
xhr.setRequestHeader('Content-Type', 'application/json');
// pass `params` to `send()` method
xhr.send(JSON.stringify(params));
// listen for `load` event
xhr.onload = () => {
console.log(xhr.responseText);
}
跨域請求和 Cookies
XMLHttpRequest
可以發送跨域請求,但需要採取特殊的安全措施。要從不同的服務器請求資源,服務器必須使用 CORS(跨域資源共享)明確支持這一點。
就像 Fetch API 一樣,XHR 不會將 cookie 和 HTTP 授權發送到另一個來源。要發送 cookie,您可以使用 withCredentials
xhr
的屬性 對象:
xhr.withCredentials = true;
XHR 與 jQuery
jQuery 包裝器方法,例如 $.ajax()
在底層使用 XHR 並提供更高級別的抽像以使開發人員的生活更輕鬆。使用 jQuery,我們可以將上面的代碼翻譯成幾行代碼:
$.ajax('https://jsonplaceholder.typicode.com/users')
.done(data => {
console.log(data);
}).fail(err => {
console.error('Error:', err);
});
XHR 與 Fetch API
Fetch API 是基於 Promise 的現代 XHR 替代方案。它簡潔、易於理解,並在 PWA Service Worker 中大量使用。
上面的 XHR 示例可以轉換為更簡單的 fetch()
- 甚至自動解析返回的 JSON 的代碼:
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('Error:', err));
想要了解更多信息? 查看 JavaScript Fetch API 指南,了解如何通過幾行代碼使用 Fetch API 來請求網絡資源。