fetch和axios區(qū)別的詳細(xì)對(duì)比舉例
一、它們是什么
| Fetch | Axios | |
|---|---|---|
| 類型 | 瀏覽器原生 API(Node 18+ 也內(nèi)置) | 第三方庫 |
| 底層 | 基于 Promise,原生實(shí)現(xiàn) | 瀏覽器基于 XMLHttpRequest,Node 端基于 http 模塊 |
| 體積 | 0(原生) | 約 15KB(gzip 后約 5KB) |
| 安裝 | 無需安裝 | npm i axios |
二、核心差異速查
| 特性 | Fetch | Axios |
|---|---|---|
HTTP 錯(cuò)誤(4xx/5xx)是否進(jìn) catch | ? 不進(jìn),需手動(dòng)判斷 res.ok | ? 自動(dòng) reject |
| 自動(dòng) JSON 解析 | ? 需 res.json() | ? 自動(dòng)解析 response.data |
| 請(qǐng)求/響應(yīng)攔截器 | ? 無(需自己封裝) | ? 內(nèi)置 |
| 請(qǐng)求超時(shí) | ? 需配合 AbortController 手動(dòng)實(shí)現(xiàn) | ? timeout 配置項(xiàng) |
| 請(qǐng)求取消 | ? AbortController | ? AbortController / CancelToken(舊) |
| 上傳/下載進(jìn)度 | ?? 僅支持下載(ReadableStream);上傳需自己實(shí)現(xiàn) | ? onUploadProgress / onDownloadProgress |
| CSRF/XSRF 防護(hù) | ? 無 | ? 內(nèi)置 xsrfCookieName |
| 默認(rèn)攜帶 cookie | ? 默認(rèn)不帶(需 credentials: 'include') | ? 同源默認(rèn)帶,跨域需 withCredentials: true |
| 自動(dòng)轉(zhuǎn)換請(qǐng)求體 | ? 需手動(dòng) JSON.stringify | ? 自動(dòng)序列化 |
| 瀏覽器兼容 | 現(xiàn)代瀏覽器,IE 不支持 | 通過 XHR 兼容到 IE11 |
| Node.js 支持 | Node 18+ 內(nèi)置 | 全版本支持 |
三、詳細(xì)對(duì)比
1. 錯(cuò)誤處理
Fetch:HTTP 錯(cuò)誤狀態(tài)不會(huì)讓 Promise reject。
fetch('/api/user/999')
.then(res => {
// 即使是 404、500,這里依然會(huì)進(jìn)入 then
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.catch(err => console.error(err));
// 只有網(wǎng)絡(luò)斷開、CORS 失敗、請(qǐng)求被中止才會(huì)進(jìn) catch
Axios:HTTP 錯(cuò)誤自動(dòng)進(jìn) catch。
axios.get('/api/user/999')
.then(res => console.log(res.data))
.catch(err => {
if (err.response) {
// 服務(wù)器返回了非 2xx
console.log(err.response.status, err.response.data);
} else if (err.request) {
// 請(qǐng)求發(fā)出但無響應(yīng)
} else {
// 配置錯(cuò)誤
}
});
2. 請(qǐng)求體與響應(yīng)體
Fetch:手動(dòng)序列化 + 手動(dòng)解析。
fetch('/api/user', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Tom' }),
})
.then(res => res.json())
.then(data => console.log(data));
Axios:自動(dòng)處理。
axios.post('/api/user', { name: 'Tom' })
.then(res => console.log(res.data));
// Content-Type 自動(dòng)設(shè)為 application/json,body 自動(dòng)序列化,data 自動(dòng)解析
3. 攔截器(Axios 殺手锏)
Axios:內(nèi)置請(qǐng)求/響應(yīng)攔截器,可統(tǒng)一加 token、統(tǒng)一處理錯(cuò)誤。
// 請(qǐng)求攔截器:每次請(qǐng)求自動(dòng)加 token
axios.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${getToken()}`;
return config;
});
// 響應(yīng)攔截器:401 自動(dòng)跳登錄頁
axios.interceptors.response.use(
res => res.data,
err => {
if (err.response?.status === 401) location.href = '/login';
return Promise.reject(err);
}
);
Fetch:沒有攔截器,要么自己封裝一層,要么用 monkey-patch:
const originalFetch = window.fetch;
window.fetch = async (url, options = {}) => {
options.headers = { ...options.headers, Authorization: `Bearer ${getToken()}` };
const res = await originalFetch(url, options);
if (res.status === 401) location.href = '/login';
return res;
};
4. 超時(shí)控制
Fetch:原生不支持,需 AbortController。
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 5000);
fetch('/api/data', { signal: controller.signal })
.finally(() => clearTimeout(timer));
Axios:一行配置。
axios.get('/api/data', { timeout: 5000 });
5. 請(qǐng)求取消
Fetch:AbortController。
const ctrl = new AbortController();
fetch('/api/data', { signal: ctrl.signal });
ctrl.abort(); // 取消
Axios:新版本同樣使用 AbortController(舊版本是 CancelToken,已廢棄)。
const ctrl = new AbortController();
axios.get('/api/data', { signal: ctrl.signal });
ctrl.abort();
6. 上傳進(jìn)度
Fetch:原生不支持(只能監(jiān)控下載,通過 ReadableStream)。
Axios:直接配置。
axios.post('/upload', formData, {
onUploadProgress: (e) => {
const percent = Math.round((e.loaded / e.total) * 100);
console.log(`已上傳 ${percent}%`);
},
});
7. 并發(fā)請(qǐng)求
Fetch:用 Promise.all。
const [user, posts] = await Promise.all([
fetch('/api/user').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
]);
Axios:同樣支持 Promise.all,舊版本另有 axios.all / axios.spread。
const [user, posts] = await Promise.all([
axios.get('/api/user'),
axios.get('/api/posts'),
]);
8. 跨域與 Cookie
Fetch:默認(rèn)不發(fā)送 Cookie。
fetch('/api/data', { credentials: 'include' }); // 跨域攜帶
fetch('/api/data', { credentials: 'same-origin' }); // 同源攜帶(默認(rèn)在某些場景)
Axios:默認(rèn)同源帶 Cookie,跨域需配置。
axios.get('/api/data', { withCredentials: true });
9. 創(chuàng)建實(shí)例
Fetch:沒有實(shí)例概念,通常自己寫一個(gè)工廠函數(shù)。
Axios:內(nèi)置實(shí)例機(jī)制,方便配置不同 baseURL。
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
headers: { 'X-Custom': 'foo' },
});
api.get('/users');
四、Fetch 簡易封裝(接近 Axios 體驗(yàn))
async function request(url, options = {}) {
const { timeout = 10000, baseURL = '', ...rest } = options;
// 超時(shí)控制
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), timeout);
// 自動(dòng) JSON
if (rest.body && typeof rest.body === 'object') {
rest.body = JSON.stringify(rest.body);
rest.headers = { 'Content-Type': 'application/json', ...rest.headers };
}
try {
const res = await fetch(baseURL + url, { ...rest, signal: ctrl.signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} finally {
clearTimeout(timer);
}
}
// 使用
request('/api/user', { method: 'POST', body: { name: 'Tom' } });
五、如何選擇
| 場景 | 推薦 |
|---|---|
| 簡單腳本、小項(xiàng)目、Demo | Fetch(零依賴) |
| 中后臺(tái)、企業(yè)項(xiàng)目 | Axios(攔截器、錯(cuò)誤處理省心) |
| 體積敏感(H5、小程序、SDK) | Fetch + 簡單封裝 |
| 需要兼容 IE | Axios |
| Node.js 服務(wù)端 | Axios(生態(tài)成熟),或 Node 18+ 原生 fetch |
| React Server Components / Next.js | Fetch(與緩存機(jī)制集成更好) |
六、總結(jié)一句話
Fetch 是底層標(biāo)準(zhǔn),Axios 是上層封裝。 一個(gè)項(xiàng)目要不要 Axios,本質(zhì)是問:"攔截器、自動(dòng) JSON、超時(shí)、錯(cuò)誤統(tǒng)一處理 —— 這些功能你愿不愿意自己寫?"
到此這篇關(guān)于fetch和axios區(qū)別的詳細(xì)對(duì)比舉例的文章就介紹到這了,更多相關(guān)fetch和axios區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript面向?qū)ο蟪绦蛟O(shè)計(jì)中對(duì)象的定義和繼承詳解
這篇文章主要介紹了JavaScript面向?qū)ο蟪绦蛟O(shè)計(jì)中對(duì)象的定義和繼承,結(jié)合實(shí)例形式詳細(xì)分析了javascript面向?qū)ο蟪绦蛟O(shè)計(jì)中對(duì)象定義、繼承、屬性、方法、深拷貝等相關(guān)概念與操作技巧,需要的朋友可以參考下2019-07-07
js實(shí)現(xiàn)動(dòng)態(tài)加載腳本的方法實(shí)例匯總
這篇文章主要介紹了js實(shí)現(xiàn)動(dòng)態(tài)加載腳本的方法,以實(shí)例形式匯總并分析了幾種常用的JavaScript動(dòng)態(tài)加載腳本的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-11-11
chrome下img加載對(duì)height()的影響示例探討
這篇文章主要介紹了chrome下img加載對(duì)height()的影響,需要的朋友可以參考下2014-05-05
解決layer彈出層的內(nèi)容頁點(diǎn)擊按鈕跳轉(zhuǎn)到新的頁面問題
今天小編就為大家分享一篇解決layer彈出層的內(nèi)容頁點(diǎn)擊按鈕跳轉(zhuǎn)到新的頁面問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09
JavaScript實(shí)現(xiàn)移動(dòng)端簽字功能
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)移動(dòng)端簽字功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
JavaScript實(shí)現(xiàn)與web通信的方法詳解
這篇文章主要介紹了JavaScript實(shí)現(xiàn)與web通信的方法詳解,文章通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08

