前端請求大比拼:Fetch、Axios、Ajax、XHR
當涉及前端網絡請求時,有許多工具/技術可供選擇,包括 Fetch、Axios、Ajax 和 XHR 等。這些技術在發送和處理HTTP請求方面提供了不同的功能和方法。本文將深入探討這些技術的特點、優勢和用法,幫你更好地理解并選擇最適合項目需求的技術。
1、基本概念
Fetch、Axios、Ajax 和XHR都是前端用于發送HTTP請求的工具或技術:
- Fetch:一種現代化的網絡請求方法,通過使用 Promise 處理異步操作,簡潔而直觀地發送HTTP請求、處理響應,并支持各種功能和API,如設置請求頭、傳遞參數、處理流數據、上傳下載文件等。
- Axios:一個基于Promise的現代化HTTP客戶端,是目前最流行的 HTTP 客戶端,可以在瀏覽器和Node.js環境中發送HTTP請求,并具有攔截請求和響應、支持并發請求、提供豐富的API等功能。
- Ajax:通過在瀏覽器和服務器之間進行異步通信,實現部分頁面更新和動態交互,提升用戶體驗;可以在不重新加載整個頁面的情況下,通過JavaScript發送HTTP請求到服務器,并處理服務器返回的數據;減少帶寬消耗,提高頁面加載速度;提高用戶交互性,實現更多的動態效果和實時更新。
- XHR:一種在瀏覽器中用于與服務器進行異步通信的API,通過發送HTTP請求并處理服務器返回的數據,實現異步獲取各種格式的數據(如XML、JSON、HTML等),以實現頁面的無刷新更新和動態交互。
下面就來看看這些技術都是怎么用的,以及都有什么特點!
2、XHR
XMLHttpRequest 是一個內置的 JavaScript 對象,XMLHttpRequest(XHR)對象用于與服務器交互。通過 XMLHttpRequest 可以在不刷新頁面的情況下請求特定 URL,獲取數據。這允許網頁在不影響用戶操作的情況下,更新頁面的局部內容。
XMLHttpRequest 在 AJAX 編程中被大量使用。盡管名稱包含XML,XMLHttpRequest 也可以用于獲取任何類型的數據,而不僅僅是 XML。它甚至支持 HTTP 以外的協議(包括 file:// 和 FTP)。
XMLHttpRequest 存在一些缺點:
- 語法復雜性:使用原始的 XMLHttpRequest 進行復雜的 AJAX 請求需要編寫更多的代碼,并手動處理狀態管理、錯誤處理等方面的邏輯。相比之下,Axios 和 Fetch API 提供了更簡單和直觀的語法,使得發送和處理 HTTP 請求更加方便。
- 功能限制:XHR 提供的功能相對較少,需要手動設置請求頭、處理超時、取消請求等。而 Axios 和 Fetch API 提供了更豐富的功能,如攔截請求和響應、自動轉換數據格式、請求取消等。
- XSRF(跨站請求偽造)保護:在 Axios 中,可以通過設置 withCredentials 選項來自動處理 XSRF 保護。然而,在 XMLHttpRequest 和 Fetch API 中,需要手動設置請求頭來實現類似的保護。
- 錯誤處理:XHR 的錯誤處理較為繁瑣,需要在回調函數中進行錯誤判斷。而 Axios 和 Fetch API 使用 Promise 和 async/await 語法,能夠更便捷地處理請求和響應的錯誤。
- 僅限于瀏覽器環境:XMLHttpRequest 是瀏覽器提供的 API,因此只能在瀏覽器環境中使用,無法在其他環境中(如服務器端)直接使用。
請求步驟
使用 XMLHttpRequest 發送請求的步驟如下:
- 創建XMLHttpRequest對象:
let xhr = new XMLHttpRequest();
- 設置請求參數:
xhr.open('GET', 'https://example.com/api/data', true);
- 設置請求頭(可選):
xhr.setRequestHeader('Content-Type', 'application/json');
- 監聽狀態變化:
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 請求成功,處理響應
console.log(xhr.responseText);
} else {
// 請求失敗
console.error('請求失敗');
}
}
};
- 發送請求:
xhr.send();
完整代碼如下:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 請求成功,處理響應
console.log(xhr.responseText);
} else {
// 請求失敗
console.error('請求失敗');
}
}
};
xhr.send();
這里創建了一個XMLHttpRequest對象,并使用open()方法設置了一個GET請求類型和URL。然后,通過監聽onreadystatechange事件來判斷請求的狀態并處理響應。當readyState為4時,表示請求已完成,此時可以通過status屬性判斷請求是否成功(200表示成功)。如果成功,可以通過responseText屬性獲取服務器返回的數據進行處理。如果失敗,將到控制臺輸出錯誤信息。
open
XMLHttpRequest 的 open() 方法用于初始化一個請求。open() 方法接受三個必填參數和一個可選參數,它們是:
- method: 表示請求的 HTTP 方法,例如 GET、POST、PUT 等。
xhr.open("GET", "https://example.com/api/data", true);
- url: 表示請求的 URL 地址。
xhr.open("GET", "https://example.com/api/data", true);
- async: 表示請求是否異步執行,即是否使用異步模式。默認為 true,表示異步執行;false 表示同步執行。
javascriptCopy Codexhr.open("GET", "https://example.com/api/data", true);
- username (可選): 表示用于進行 HTTP 認證的用戶名。
xhr.open("GET", "https://example.com/api/data", true, "username");
- password (可選): 表示用于進行 HTTP 認證的密碼。
xhr.open("GET", "https://example.com/api/data", true, "username", "password");
綜合起來,open() 方法的完整語法如下:
xhr.open(method, url, async, username, password);
請求頭和響應頭
可以使用 setRequestHeader() 方法設置 XMLHttpRequest 的請求頭。這個方法接受兩個參數:頭字段的名稱和值。
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("Authorization", "Bearer token123");
這里使用 setRequestHeader() 方法設置了兩個請求頭:Content-Type 和 Authorization。第一個參數是頭字段的名稱,第二個參數是頭字段的值。
可以使用 getResponseHeader() 方法或者 getAllResponseHeaders() 方法來獲取 XMLHttpRequest 的響應頭。
- getResponseHeader():通過指定頭字段的名稱,可以獲取指定的響應頭字段的值。
const contentType = xhr.getResponseHeader("Content-Type");
這里使用 getResponseHeader() 方法獲取了名為 Content-Type的響應頭字段的值。
- getAllResponseHeaders()** **:該方法返回一個包含所有響應頭信息的字符串。
const headers = xhr.getAllResponseHeaders();
這里使用 getAllResponseHeaders() 方法獲取了所有響應頭信息,并將其存儲在名為 headers 的變量中。
這里返回的 headers 是一個包含所有響應頭信息的字符串。該字符串中每一行表示一個響應頭字段,具有以下形式:
HeaderName: HeaderValue
例如,如果響應頭中包含 Content-Type 和 Authorization 字段,那么返回的 headers 字符串可能如下所示:
Content-Type: application/json
Authorization: Bearer token123
可以使用適當的方法(如字符串解析)將這個字符串進行進一步處理,以獲取特定的響應頭字段的名稱和值。
注意,要在調用 open() 方法之后、發送請求之前使用 setRequestHeader() 方法來設置請求頭,以確保設置能夠生效。同樣,要在接收到響應之后才能使用 getResponseHeader() 或 getAllResponseHeaders() 來獲取響應頭信息。
readyState
上面示例中的 readyState 是 XMLHttpRequest 對象的一個屬性,用于表示請求的狀態。該屬性有以下五種可能的取值:
- 0 (未初始化): XMLHttpRequest 對象已創建,但尚未調用 open 方法。
- 1 (載入中): open 方法已調用,但尚未調用 send 方法。
- 2 (載入完成): send 方法已調用,并且響應頭和響應狀態已經可用。
- 3 (交互中): 正在接收響應數據,此時部分響應內容可能已經可以訪問了。
- 4 (完成): 響應數據接收完成,整個請求過程已經完全結束。
通常情況下,我們主要關注 readyState 為 4 的狀態,即請求完成狀態。在這個狀態下,我們可以通過檢查 status 屬性來獲取請求的結果(比如響應狀態碼),并通過 responseText 或 responseXML 屬性來獲取服務器返回的數據。
注意,readyState 屬性是只讀的,我們不能直接修改它的值。它會在請求過程中自動更新,我們可以通過監聽 readystatechange 事件來進行相應的處理。
status
status 是 XMLHttpRequest 對象的一個屬性,用于表示 HTTP 狀態碼。 HTTP 狀態碼是服務器對請求處理的結果進行響應的標準化數字代碼。常見的一些 HTTP 狀態碼包括:
- 200 OK:表示請求成功并返回所請求的數據。
- 201 Created:表示請求成功并在服務器上創建了新資源。
- 204 No Content:表示請求成功,但響應中無返回的內容。
- 400 Bad Request:表示請求有語法錯誤或參數錯誤,服務器無法理解。
- 401 Unauthorized:表示請求未經授權,需要用戶進行身份驗證。
- 403 Forbidden:表示服務器拒絕請求,通常是因為請求的資源沒有訪問權限。
- 404 Not Found:表示請求的資源不存在。
- 500 Internal Server Error:表示服務器內部發生錯誤,無法完成請求。
在使用 XMLHttpRequest 發送請求后,可以通過檢查 status 屬性來獲取服務器對請求的響應狀態碼,并根據不同的狀態碼進行相應的處理。
事件屬性
XMLHttpRequest (XHR) 對象具有以下常用的事件屬性:
- onreadystatechange: 當 readyState 屬性發生變化時觸發該事件。可以使用 xhr.onreadystatechange 屬性來指定處理狀態變化的回調函數。在每次狀態變化時都會觸發該事件,可以通過檢查 xhr.readyState 屬性來確定當前的狀態。
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
// 請求已完成
if(xhr.status === 200) {
// 請求成功
} else {
// 請求失敗
}
} else {
// 請求進行中
}
};
- onload: 當請求成功完成并且響應數據完全加載時觸發該事件。可以使用 xhr.onload 屬性來指定處理成功加載的回調函數。通常在這個事件中獲取和處理響應數據。
xhr.onload = () => {
// 獲取和處理響應數據
const responseData = JSON.parse(xhr.responseText);
// 其他操作...
};
- onerror: 當請求發生錯誤時觸發該事件。可以使用 xhr.onerror 屬性來指定處理錯誤的回調函數。常見的錯誤包括網絡錯誤、無法完成請求等。
xhr.onerror = () => {
// 處理錯誤邏輯
};
- onprogress: 在數據傳輸過程中持續觸發,用于追蹤請求的進度。可以使用 xhr.onprogress 屬性來指定處理進度的回調函數。
xhr.onprogress = (event) => {
// 處理進度邏輯
};
- ontimeout: 當請求超時時觸發該事件。可以使用 xhr.ontimeout 屬性來指定處理超時的回調函數。
xhr.ontimeout = () => {
// 處理超時邏輯
};
responseType
responseType 是 XMLHttpRequest 對象的屬性,用于指定響應的數據類型。它決定了如何解析從服務器返回的響應數據。 常見的 responseType 值包括:
- "" (默認值): 表示響應的數據類型是字符串。
xhr.responseType = "";
- "text": 表示響應的數據類型是字符串。
xhr.responseType = "text";
- "json": 表示響應的數據類型是 JSON 對象,會自動將響應數據解析為 JavaScript 對象。
xhr.responseType = "json";
- "document": 表示響應的數據類型是 XML 文檔對象,會自動將響應數據解析為 XML 文檔對象。
xhr.responseType = "document";
- "arraybuffer": 表示響應的數據類型是 ArrayBuffer 對象,適用于二進制數據的傳輸和處理。
xhr.responseType = "arraybuffer";
- "blob": 表示響應的數據類型是 Blob 對象,適用于文件下載等場景。
xhr.responseType = "blob";
通過設置不同的 responseType 值,可以根據需要獲取不同類型的響應數據。注意,在設置 responseType 之前,最好在調用 open 方法之后、發送請求之前設置,以確保設置生效。
3、Ajax
AJAX(Asynchronous JavaScript and XML,異步 JavaScript 和 XML)是一種使用現有的網頁技術來創建異步請求和更新頁面內容的方法。Ajax 本身不是一種技術,而是一種將一些現有技術結合起來使用的方法,包括:HTML 或 XHTML、CSS、JavaScript、DOM、XML、XSLT、以及最重要的 XMLHttpRequest 對象。
當使用結合了這些技術的 Ajax 模型以后,網頁應用能夠快速地將增量更新呈現在用戶界面上,而不需要重載(刷新)整個頁面。這使得程序能夠更快地回應用戶的操作。Ajax 最吸引人的特性是它的“異步”性質,這意味著它可以與服務器通信、交換數據并更新頁面,而無需刷新頁面。
Ajax 是一種使用瀏覽器提供的 XMLHttpRequest 對象實現的技術,用于在不刷新整個頁面的情況下進行異步請求和更新頁面內容。可以說 Ajax 是基于瀏覽器提供的 XMLHttpRequest 對象來實現的。
以下是基于原生 JavaScript 的 AJAX 請求代碼示例:
// 創建 XMLHttpRequest 對象
const xhr = new XMLHttpRequest();
// 指定請求的方法和 URL
xhr.open('GET', 'api_url', true); // 第三個參數 true 表示異步請求
// 設置請求頭(如果需要)
xhr.setRequestHeader('Content-Type', 'application/json'); // 根據實際需求設置請求頭
// 注冊一個回調函數來處理響應
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
const response = JSON.parse(xhr.responseText); // 處理響應數據
// 在這里執行相應的操作
console.log(response);
}
};
// 發送請求
xhr.send();
雖然 AJAX 是一種強大的技術,但相對于 Axios 和 Fetch API,它有以下一些缺點:
- 兼容性問題:AJAX 的兼容性相對較低,尤其在舊版本的瀏覽器中可能會出現問題。而 Axios 和 Fetch API 使用了更現代的 JavaScript 特性,具有更好的兼容性。
- 代碼冗余:使用原生的 AJAX 需要編寫較多的代碼來處理不同的狀態碼、錯誤處理以及請求的拼裝等。而 Axios 和 Fetch API 提供了更簡潔和易用的接口,減少了代碼冗余。
- 缺乏默認配置:AJAX 不提供默認的全局配置,如請求和響應攔截器、統一的錯誤處理等。而 Axios 和 Fetch API 支持全局配置,并且提供了更方便的攔截器機制。
- 功能限制:AJAX 在處理跨域請求時需要注意添加額外的處理,比如設置 CORS 頭部信息或者使用 JSONP。而 Axios 和 Fetch API 提供了更直接的方式來處理跨域請求。
- 可讀性較差:由于 AJAX 使用的是回調函數來處理異步請求,可能會導致代碼邏輯比較復雜,可讀性較差。而 Axios 和 Fetch API 使用的是 Promise 或 async/await,使代碼結構更加清晰易讀。
4、Fetch
Fetch 是一種用于進行網絡請求的現代 JavaScript API。它提供了一種簡單、靈活且功能強大的方式,用于從服務器獲取資源并處理響應。
Fetch API 在瀏覽器中原生支持,并且以 Promise 為基礎,使得異步請求更加直觀和易用。使用 Fetch API,可以執行各種類型的請求(如 GET、POST、PUT、DELETE 等),發送請求時可以設置請求頭、請求參數,以及處理響應數據。
與傳統的 AJAX 相比,Fetch API 具有以下優點:
- Promise 支持:Fetch API 使用 Promise 對象來處理異步操作,使得處理異步請求的流程更加清晰、易于閱讀和編寫。
- 更簡潔的 API:Fetch API 提供了一個簡潔的 API,使發送請求變得更加直觀和簡單,同時提供了豐富的配置選項(如設置請求頭、請求參數等)。
- 內置的 JSON 解析:在處理響應時,Fetch API 內置了對 JSON 數據的解析,無需手動進行解析操作。
- 更好的錯誤處理:Fetch API 使用了更全面的錯誤處理機制,允許通過檢查響應狀態碼來確定請求是否成功,并以不同的方式處理錯誤。
fetch()
Fetch API 提供了一個全局的 fetch() 方法,該方法提供了一種簡單、邏輯的方式來通過網絡異步獲取資源。
fetch() 方法的語法如下:
fetch(url, options)
.then(response => {
// 在這里處理響應
})
.catch(error => {
// 在這里處理錯誤
});
這里有兩個參數:
- url:請求的 URL 地址。
- options(可選):一個包含請求選項的對象,可以指定請求的方法(method)、請求頭(headers)、請求體(body)等。
注意,fetch()默認使用的是 GET 請求,如果需要使用其他方法(如 POST、PUT 等),需要通過 options 參數進行設置。
fetch() 方法返回一個 Promise 對象,可以使用 .then() 方法來處理成功的響應,使用 .catch() 方法來處理錯誤的情況。
- 在 .then() 中,可以訪問到 response 對象,進一步處理響應的內容。
- 在 .catch() 中,我們可以訪問到 error 對象,用于處理請求過程中的任何錯誤。
options 對象包含的屬性如下:
{
method: 'POST', // *GET, POST, PUT, DELETE等
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *client
body: JSON.stringify(data)
// body 數據類型必須與 "Content-Type" 請求頭匹配
}
- method:請求方法,例如 GET、POST、PUT、DELETE 等。
- mode:請求模式,可以是 no-cors、*cors、same-origin 等。
- cache:緩存模式,可以是 default、no-cache、reload、force-cache、only-if-cached 等。
- credentials:請求的憑證模式,可以是 include、*same-origin、omit 等。
- headers:請求頭對象,用于設置請求頭的鍵值對。
- redirect:重定向模式,可以是 manual、*follow、error 等。
- referrerPolicy:引用頁面隱私設置,可以是 no-referrer、*client 等。
- body:請求體數據,必須與 "Content-Type" 請求頭指定的數據類型匹配。在示例中,使用JSON.stringify()將數據轉換為 JSON 字符串。
response
一旦獲取到響應(Response),返回的對象包含以下屬性:
- response.body:一個簡單的 getter,提供了響應內容的可讀流(ReadableStream)。
- response.bodyUsed:一個布爾值,用于記錄響應體是否已經被使用過。
- response.headers:與響應相關聯的頭部信息對象。
- response.ok:一個布爾值,指示響應是否成功。
- response.redirected:指示響應是否是重定向結果的布爾值。
- response.status:響應的狀態碼。
- response.statusText:與狀態碼對應的狀態消息。
- response.type:響應的類型。
- response.url:響應的 URL。
我們可以使用 response.type 來確定響應的類型,并根據不同的類型采取相應的處理方法:
fetch(url)
.then(response => {
// 檢查響應狀態碼
if (!response.ok) {
throw new Error('Network response was not ok');
}
// 定義一個響應類型與解析方法的映射關系
const responseTypes = new Map([
['json', () => response.json()],
['text', () => response.text()],
['formData', () => response.formData()],
['blob', () => response.blob()],
['arrayBuffer', () => response.arrayBuffer()]
]);
// 根據響應類型選擇相應的解析方法
const parser = responseTypes.get(response.type);
if (parser) {
return parser();
} else {
throw new Error('Unsupported response type');
}
})
.then(data => {
// 處理數據
console.log(data);
})
.catch(error => {
// 處理錯誤情況
console.error('Error:', error);
});
Response 對象提供了 5 個方法,用于從 HTTP 響應中獲取不同類型的數據:
- response.json():將響應體解析為 JSON 對象。如果響應的 Content-Type 是 application/json,則使用此方法。
- response.text():將響應體解析為文本字符串。如果響應的 Content-Type 是純文本類型,如 text/plain 或 text/html,則使用此方法。
- response.formData():將響應體解析為 FormData 對象。如果響應的 Content-Type 是 multipart/form-data,則使用此方法。FormData 通常用于上傳文件或提交表單數據。
- response.blob():將響應體解析為 Blob 對象。Blob 對象表示二進制大對象,可以是圖像、音頻、視頻等類型的數據。
- response.arrayBuffer():將響應體解析為 ArrayBuffer 對象。ArrayBuffer 是一種表示二進制數據的固定長度緩沖區。
這些方法返回一個 Promise,當解析完成時,Promise 將被解析為相應的數據類型。
請求頭和響應頭
fetch 函數的請求頭包含在發起 HTTP 請求時發送給服務器的信息,用于傳遞額外的參數和配置。可以使用 headers 對象來設置和操作請求頭。常見的請求頭字段包括:
- Content-Type:指定請求體的格式類型,如 application/json、application/x-www-form-urlencoded 等。
- Authorization:用于身份驗證,通常與 Token 或用戶名密碼一起使用。
- Accept:指定客戶端所能接受的響應數據類型。
- User-Agent:標識發起請求的用戶代理(瀏覽器或應用程序)的信息。
在 fetch 函數中可以通過第二個參數進行配置,其中可以指定請求頭:
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
}
})
.then(response => {
// 處理響應
})
.catch(error => {
// 處理錯誤
});
響應頭是服務器在響應 HTTP 請求時發送給客戶端的頭部信息。可以通過 Response 對象的 headers 屬性訪問響應頭。常見的響應頭字段包括:
- Content-Type:指定響應體的格式類型。
- Set-Cookie:設置或修改客戶端的 Cookie。
- Cache-Control:控制緩存的行為,如 no-cache、max-age 等。
- Content-Disposition:指定響應的內容該如何展示(如文件的下載)。
在處理 fetch 返回的 Response 對象時,可以通過調用 response.headers.get('Header-Name') 方法來獲取特定的響應頭字段的值。
fetch(url)
.then(response => {
const contentType = response.headers.get('Content-Type');
// 其他處理邏輯
})
.catch(error => {
// 處理錯誤
});
錯誤處理
除了可以使用 catch() 來處理錯誤之外,與使用其他異步操作一樣,我們也可以使用 async/await 來處理異步請求,使代碼更加簡潔和易讀:
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (response.ok) {
const data = await response.json();
console.log(data); // 處理解析后的數據
} else {
throw new Error('請求失敗');
}
} catch (error) {
console.log(error); // 處理錯誤
}
}
fetchData();
取消請求
在標準的 Fetch API 中,沒有提供直接取消 Fetch 請求的內置方法。但是,可以使用以下方法來模擬或實現取消 Fetch 請求的效果。
使用 AbortController 和 AbortSignal:這是一種較新的瀏覽器特性,用于生成可以取消請求的信號。可以創建一個 AbortController對象,然后將其關聯到 Fetch 請求中,當需要取消請求時,調用 AbortController 的 abort()方法:
// 創建 AbortController 和關聯的 signal
const abortController = new AbortController();
const signal = abortController.signal;
// 發起 Fetch 請求,并將 signal 傳遞給 fetch 函數
fetch(url, { signal })
.then(response => {
// 處理響應
})
.catch(error => {
if (error.name === 'AbortError') {
// 請求已被取消
} else {
// 處理其他錯誤
}
});
// 當需要取消請求時,調用 abort() 方法
abortController.abort();
瀏覽器兼容
目前,主流瀏覽器都支持 Fetch API:
圖片
5、Axios
Axios 是一個基于 Promise 網絡請求庫,用于在瀏覽器和 Node.js 中進行 HTTP 請求。在服務端它使用原生 node.js http 模塊, 而在客戶端 (瀏覽端) 則使用 XMLHttpRequests。Axios 是目前最流行的 HTTP 請求庫,其 npm 每周下載量達到了 4500w+。
Axios 庫具有以下特點:
- 瀏覽器和 Node.js:Axios 可在瀏覽器和 Node.js 環境中使用,可以在不同的平臺上執行 HTTP 請求。
- Promise API:Axios 使用 Promise API 進行異步操作,能夠更輕松地處理異步請求和響應。
- 請求攔截和響應攔截:可以通過攔截器,在請求發送之前或響應返回之后對請求進行全局性或個性化的變換和處理。可以在請求或響應的不同階段添加公共的請求頭、驗證身份、處理錯誤等。
- 取消請求:Axios 允許取消未完成的請求,以避免無效的請求,并減輕服務器的負擔。取消請求可以通過創建取消令牌、使用取消令牌進行請求配置或者在攔截器中中斷請求來實現。
- 并發請求:Axios 提供了執行多個并發請求的能力,可以同時發起多個請求,并在所有請求完成后進行處理。
- 自動轉換數據:Axios 可以自動將請求和響應的數據進行格式轉換,包括 JSON、URL 編碼等。無需手動處理數據轉換的過程。
- 錯誤處理機制:當請求過程中出現錯誤時,Axios 會返回詳細的錯誤信息,包括 HTTP 錯誤狀態碼、錯誤描述等。可以根據需要對這些錯誤進行處理和顯示。
- 簡潔的 API:Axios 的 API 設計簡潔易用,具有直觀的方法命名和參數配置。可以輕松地使用 Axios 進行 GET、POST、PUT、DELETE 等常見的 HTTP 請求。
可以通過以下命令來安裝 Axios:
// 使用 npm 安裝
npm install axios
// 使用 yarn 安裝
yarn add axios
下面來進行一個簡單的 get 請求:
axios.get('https://api.example.com/data')
.then(response => {
// 處理成功響應
console.log(response.data);
})
.catch(error => {
// 處理錯誤
console.error(error);
});
這里使用 axios.get 方法發起了一個 GET 請求,并將請求的 URL 作為參數傳遞給該方法。然后使用 Promise 的 .then 方法處理成功響應,并通過 response.data 獲取響應數據。如果請求失敗,可以通過 Promise 的 .catch 方法捕獲錯誤。
請求方法
axios 支持通過簡寫方式來執行不同類型的請求:
- axios.request(config)
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.head(url[, config])
- axios.options(url[, config])
- axios.post(url[, data[, config]])
- axios.put(url[, data[, config]])
- axios.patch(url[, data[, config]])
對于這些方法,第一個參數是請求的 URL,config 和 data 分別是請求的配置項和請求參數,這兩個參數都是可選的。例如,下面是一個 post 請求:
const options = {
headers: {'X-Custom-Header': 'value'}
};
axios.post('/save', { a: 10 }, options)
.then(response => {
// 處理成功響應
console.log(response.data);
})
.catch(error => {
// 處理錯誤
console.error(error);
});
當作為第二個參數傳遞給 axios.post 函數時,Axios 會自動將 JavaScript 對象序列化為 JSON。 這樣就無需將 POST 正文序列化為 JSON。Axios 還會自動將 Content-Type 請求頭設置為 application/json。
多個請求
在 Axios 中,可以使用 axios.all 和 axios.spread 來處理多個并發的請求:
const axios = require('axios');
// 創建多個請求
const request1 = axios.get('https://api.example.com/data1');
const request2 = axios.get('https://api.example.com/data2');
// 并發發送多個請求
axios.all([request1, request2])
.then(axios.spread((response1, response2) => {
// 處理各個請求的響應
console.log(response1.data);
console.log(response2.data);
}))
.catch(error => {
// 處理錯誤
console.error(error);
});
可以看到,在 .then 方法中使用了 axios.spread 函數將多個請求的響應結果進行解構,通過多個參數分別接收各個請求的響應。可以根據實際情況命名這些參數,并通過 response1.data、response2.data 等方式獲取各個請求的響應數據。
請求攔截、響應攔截
在 Axios 中,可以使用 transformRequest 方法在請求發送之前對請求數據進行轉換和處理,它是一個請求攔截器,是一個可選的函數。
transformRequest 函數接收兩個參數:requestData 和 requestHeaders。其中,requestData 是要發送的請求數據,requestHeaders 是要發送的請求頭信息。可以在 transformRequest 函數內部對這些參數進行修改,并將修改后的值返回。返回的結果將作為實際發送請求的數據。
axios({
url: 'https://api.example.com/data',
method: 'post',
data: {
id: 12345,
name: 'John Doe'
},
transformRequest: (data, headers) => {
// 對請求數據進行轉換和處理
const modifiedData = { ...data }; // 復制原始數據
// 修改數據或添加額外字段
modifiedData.extraField = 'Extra Value';
// 修改請求頭信息
headers['Content-Type'] = 'application/json';
return JSON.stringify(modifiedData); // 返回處理后的數據
}
})
.then(response => {
// 處理成功響應
console.log(response.data);
})
.catch(error => {
// 處理錯誤
console.error(error);
});
這里使用 Axios 發起了一個 POST 請求。通過傳遞包含 transformRequest 函數的配置對象來定義請求。在 transformRequest 函數內部,復制了原始的請求數據 data,并進行了一些修改和處理,如添加了額外的字段和修改了請求頭信息。最終,將修改后的數據以 JSON 字符串的形式返回。Axios 將使用 transformRequest 函數返回的結果作為實際發送請求的數據。
除了可以對請求進行攔截之外,Axios 還支持對響應進行攔截,對響應數據進行轉換和處理。可以通過 transformResponse 響應攔截器來實現。該函數接收一個參數:responseData,它是從服務器接收到的原始響應數據。可以在 transformResponse 函數內部對這個參數進行修改,并將修改后的值返回。返回的結果將作為實際處理響應的數據。
axios.get('https://api.example.com/data', {
transformResponse: (data) => {
// 對響應數據進行轉換和處理
const parsedData = JSON.parse(data); // 解析 JSON 字符串
// 修改數據或添加額外字段
parsedData.extraField = 'Extra Value';
return parsedData; // 返回處理后的數據
}
})
.then(response => {
// 處理成功響應
console.log(response.data);
})
.catch(error => {
// 處理錯誤
console.error(error);
});
這里使用 Axios 發起了一個 GET 請求,并通過傳遞包含 transformResponse 函數的配置對象來定義請求。在 transformResponse 函數內部,對從服務器接收到的響應數據 data 進行了一些修改和處理,如解析 JSON 字符串,添加了額外的字段。最終將修改后的數據返回。
攔截請求和響應
Axios 中,可以使用攔截器來攔截請求和響應,并在其被發送或接收之前進行一些額外的處理,可以通過 axios.interceptors 對象來添加攔截器。
// 添加請求攔截器
axios.interceptors.request.use(config => {
// 在發送請求之前做一些處理
console.log('請求攔截器');
// 修改請求配置
config.headers['Authorization'] = 'Bearer token';
return config;
}, error => {
// 處理請求錯誤
console.error('請求出錯:', error);
});
// 添加響應攔截器
axios.interceptors.response.use(response => {
// 在接收到響應數據之前做一些處理
console.log('響應攔截器');
// 修改響應數據
response.data = { ...response.data, extraField: 'Extra Value' };
return response;
}, error => {
// 處理響應錯誤
console.error('響應出錯:', error);
});
// 發送請求
axios.get('https://api.example.com/data')
.then(response => {
// 處理成功響應
console.log(response.data);
})
.catch(error => {
// 處理請求或響應錯誤
console.error(error);
});
這里首先使用 axios.interceptors.request.use 方法添加了一個請求攔截器。該攔截器在發送請求之前被調用,并接收請求配置對象 config 作為參數。可以對請求配置進行修改,如添加請求頭信息。最后,要確保返回修改后的配置對象。
接下來,使用 axios.interceptors.response.use 方法添加了一個響應攔截器。該攔截器在接收到響應數據之前被調用,并接收響應對象 response 作為參數。可以對響應數據進行修改,如添加額外的字段。同樣,要確保返回修改后的響應對象。
客戶端支持 XSRF 防護
跨站請求偽造(簡稱 XSRF)是一種攻擊 Web 應用的方法,其中攻擊者將自己偽裝成合法且受信任的用戶,以影響應用程序與用戶瀏覽器之間的交互。 有很多方法可以執行此類攻擊,包括 XMLHttpRequest。
幸運的是,Axios 通過允許在發出請求時嵌入額外的身份驗證數據來防止 XSRF。 這使得服務器能夠發現來自未經授權的位置的請求。以下是使用 Axios 完成此操作的方法:
const options = {
method: 'post',
url: '/login',
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
};
axios(options)
.then(response => {
// 處理成功響應
console.log(response.data);
})
.catch(error => {
// 處理請求錯誤
console.error(error);
});
這里有兩個 xsrf 相關的屬性:
- xsrfCookieName: 'XSRF-TOKEN':用于跨站請求偽造(XSRF/CSRF)保護的配置選項之一。它指定了存儲 XSRF 令牌的 cookie 的名稱。XSRF 令牌用于防止惡意網站發起對已驗證用戶的請求。
- xsrfHeaderName: 'X-XSRF-TOKEN':用于跨站請求偽造(XSRF/CSRF)保護的配置選項之一。它指定了包含 XSRF 令牌的請求頭的名稱。服務器端可以通過檢查該請求頭來驗證請求的合法性。
請求進度
Axios 的另一個有趣的功能是能夠監控請求的進度,這在下載或上傳大文件時特別有用,可以使用 onUploadProgress 和 onDownloadProgress 兩個配置選項來實現。
對于上傳進度,可以使用 onUploadProgress 配置選項。它會在上傳數據時觸發,并提供關于上傳進度的信息。
axios.post('/upload', data, {
onUploadProgress: progressEvent => {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
console.log(`上傳進度:${percentCompleted}%`);
},
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
這里發送了一個 POST 請求,在配置選項中使用了 onUploadProgress。當數據上傳過程中觸發進度事件時,回調函數會被執行。在回調函數中,我們計算出了已上傳數據的百分比,并將其打印出來。
對于下載進度,可以使用 onDownloadProgress 配置選項。它會在接收到響應數據時觸發,并提供關于下載進度的信息。
axios.get('/download', {
onDownloadProgress: progressEvent => {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
console.log(`下載進度:${percentCompleted}%`);
},
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
這里發送了一個 GET 請求,在配置選項中使用了 onDownloadProgress。當數據下載過程中觸發進度事件時,回調函數會被執行。在回調函數中,我們計算出了已下載數據的百分比,并將其打印出來。
取消請求
在 Axios 中,可以使用取消令牌(cancel token)來取消請求。取消令牌是一個對象,它表示一個具體的取消操作,并允許在需要時中止請求。
// 創建一個取消令牌源
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
// 發送請求
axios.get('/api/data', {
cancelToken: source.token
})
.then(response => {
console.log(response.data);
})
.catch(error => {
if (axios.isCancel(error)) {
console.log('請求已被取消:', error.message);
} else {
console.error(error);
}
});
// 取消請求
source.cancel('取消請求的原因');
這里,先創建了一個取消令牌源 source。然后,發送 GET 請求時將 cancelToken 配置選項設置為 source.token,即將取消令牌與該請求關聯起來。當需要取消請求時,調用 source.cancel() 方法,并傳入取消請求的原因作為參數。
在請求的 .catch() 方法中,我們使用 axios.isCancel(error) 來判斷捕獲的錯誤是否是一個已取消的請求。如果是取消請求導致的錯誤,則會打印出 '請求已被取消' 的提示信息。否則,將打印出其他類型的錯誤。
請求超時
可以使用 timeout 配置選項設置 Axios 請求的超時時間,這個選項指定了請求在多少毫秒后如果沒有得到響應就會超時。
axios.get('/api/data', {
timeout: 5000 // 設置超時時間為5秒
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
發送了一個 GET 請求,并在配置選項中設置了 timeout 為 5000 毫秒(即 5 秒)。如果請求在 5 秒內沒有得到響應,就會觸發超時錯誤。在超時錯誤的情況下,請求會被自動取消,并且進入 .catch() 分支。您可以根據需要進行錯誤處理。
注意,如果不設置 timeout 選項,默認情況下 Axios 請求是沒有超時限制的。
6、小結
相對于 Fetch、XMLHttpRequest 和 Ajax,我還是更喜歡 Axios。它提供了簡潔易用的 API,統一的錯誤處理和攔截器支持,取消請求和超時處理功能,以及基于 Promise 的鏈式調用和跨瀏覽器兼容性。這些特性使得使用 Axios 更方便、高效,并提供更好的開發體驗。