fetch和axios区别

一、它们是什么

Fetch Axios
类型 浏览器原生 API(Node 18+ 也内置) 第三方库
底层 基于 Promise,原生实现 浏览器基于 XMLHttpRequest,Node 端基于 http 模块
体积 0(原生) 约 15KB(gzip 后约 5KB)
安装 无需安装 npm i axios

二、核心差异速查

特性 Fetch Axios
HTTP 错误(4xx/5xx)是否进 catch ❌ 不进,需手动判断 res.ok ✅ 自动 reject
自动 JSON 解析 ❌ 需 res.json() ✅ 自动解析 response.data
请求/响应拦截器 ❌ 无(需自己封装) ✅ 内置
请求超时 ❌ 需配合 AbortController 手动实现 timeout 配置项
请求取消 AbortController AbortController / CancelToken(旧)
上传/下载进度 ⚠️ 仅支持下载(ReadableStream);上传需自己实现 onUploadProgress / onDownloadProgress
CSRF/XSRF 防护 ❌ 无 ✅ 内置 xsrfCookieName
默认携带 cookie ❌ 默认不带(需 credentials: 'include' ✅ 同源默认带,跨域需 withCredentials: true
自动转换请求体 ❌ 需手动 JSON.stringify ✅ 自动序列化
浏览器兼容 现代浏览器,IE 不支持 通过 XHR 兼容到 IE11
Node.js 支持 Node 18+ 内置 全版本支持

三、详细对比

1. 错误处理

Fetch:HTTP 错误状态不会让 Promise reject。

js 复制代码
fetch('/api/user/999')
  .then(res => {
    // 即使是 404、500,这里依然会进入 then
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();
  })
  .catch(err => console.error(err));
// 只有网络断开、CORS 失败、请求被中止才会进 catch

Axios:HTTP 错误自动进 catch。

js 复制代码
axios.get('/api/user/999')
  .then(res => console.log(res.data))
  .catch(err => {
    if (err.response) {
      // 服务器返回了非 2xx
      console.log(err.response.status, err.response.data);
    } else if (err.request) {
      // 请求发出但无响应
    } else {
      // 配置错误
    }
  });

2. 请求体与响应体

Fetch:手动序列化 + 手动解析。

js 复制代码
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:自动处理。

js 复制代码
axios.post('/api/user', { name: 'Tom' })
  .then(res => console.log(res.data));
// Content-Type 自动设为 application/json,body 自动序列化,data 自动解析

3. 拦截器(Axios 杀手锏)

Axios:内置请求/响应拦截器,可统一加 token、统一处理错误。

js 复制代码
// 请求拦截器:每次请求自动加 token
axios.interceptors.request.use(config => {
  config.headers.Authorization = `Bearer ${getToken()}`;
  return config;
});

// 响应拦截器:401 自动跳登录页
axios.interceptors.response.use(
  res => res.data,
  err => {
    if (err.response?.status === 401) location.href = '/login';
    return Promise.reject(err);
  }
);

Fetch:没有拦截器 ,要么自己封装一层,要么用 monkey-patch

js 复制代码
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. 超时控制

Fetch:原生不支持,需 AbortController

js 复制代码
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 5000);

fetch('/api/data', { signal: controller.signal })
  .finally(() => clearTimeout(timer));

Axios:一行配置。

js 复制代码
axios.get('/api/data', { timeout: 5000 });

5. 请求取消

Fetch:AbortController

js 复制代码
const ctrl = new AbortController();
fetch('/api/data', { signal: ctrl.signal });
ctrl.abort(); // 取消

Axios:新版本同样使用 AbortController (旧版本是 CancelToken,已废弃)。

js 复制代码
const ctrl = new AbortController();
axios.get('/api/data', { signal: ctrl.signal });
ctrl.abort();

6. 上传进度

Fetch:原生不支持 (只能监控下载,通过 ReadableStream)。

Axios:直接配置。

js 复制代码
axios.post('/upload', formData, {
  onUploadProgress: (e) => {
    const percent = Math.round((e.loaded / e.total) * 100);
    console.log(`已上传 ${percent}%`);
  },
});

7. 并发请求

Fetch:用 Promise.all

js 复制代码
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

js 复制代码
const [user, posts] = await Promise.all([
  axios.get('/api/user'),
  axios.get('/api/posts'),
]);

Fetch:默认不发送 Cookie。

js 复制代码
fetch('/api/data', { credentials: 'include' }); // 跨域携带
fetch('/api/data', { credentials: 'same-origin' }); // 同源携带(默认在某些场景)

Axios:默认同源带 Cookie,跨域需配置。

js 复制代码
axios.get('/api/data', { withCredentials: true });

9. 创建实例

Fetch:没有实例概念,通常自己写一个工厂函数。

Axios:内置实例机制,方便配置不同 baseURL。

js 复制代码
const api = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000,
  headers: { 'X-Custom': 'foo' },
});

api.get('/users');

四、Fetch 简易封装(接近 Axios 体验)

js 复制代码
async function request(url, options = {}) {
  const { timeout = 10000, baseURL = '', ...rest } = options;

  // 超时控制
  const ctrl = new AbortController();
  const timer = setTimeout(() => ctrl.abort(), timeout);

  // 自动 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' } });

五、如何选择

场景 推荐
简单脚本、小项目、Demo Fetch(零依赖)
中后台、企业项目 Axios(拦截器、错误处理省心)
体积敏感(H5、小程序、SDK) Fetch + 简单封装
需要兼容 IE Axios
Node.js 服务端 Axios(生态成熟),或 Node 18+ 原生 fetch
React Server Components / Next.js Fetch(与缓存机制集成更好)

六、总结一句话

Fetch 是底层标准,Axios 是上层封装。 一个项目要不要 Axios,本质是问:"拦截器、自动 JSON、超时、错误统一处理 ------ 这些功能你愿不愿意自己写?"

相关推荐
黄贵根2 小时前
JavaScript实现教培行业意向登记系统
开发语言·javascript·ecmascript
codeGoogle5 小时前
自研 IM 还是选择第三方 SDK?企业开发者应该如何权衡?
前端·后端·程序员
zzzzzz3106 小时前
从 react-bits 看动效组件化:别把视觉效果写成一次性页面代码
javascript·react.js·开源
用户938515635077 小时前
React Context 与自定义 Hook 从底层到实践:「跨层级通信 + 副作用封装」全解析
前端·javascript·react.js
滴滴答答哒7 小时前
VUE3+element-plus MultiSelect 多选下拉组件
前端·javascript·vue.js
其美杰布-富贵-李7 小时前
04 watch 与 Vue 响应式数据流
前端·javascript·vue.js
赵大仁9 小时前
生成式 UI 实战:用 JSON Schema + React 动态渲染 AI 界面
前端·ai·react·next.js·前端架构·生成式ui
kyriewen10 小时前
我排查了一个React内存泄漏——罪魁祸首是这3个被忽略的清理函数
前端·javascript·面试
IT_陈寒10 小时前
我又被JavaScript的隐式类型转换坑了
前端·人工智能·后端