☰
原生Fetch API与axios对比:现代前端HTTP请求的最佳实践
2026/11/4 2:55:18 网站建设 项目流程

1. 为什么我们需要重新审视原生Fetch API

最近在review一个前端项目的依赖项时,我发现axios这个"老熟人"占据了不小的体积(约12KB gzipped)。这让我开始思考:在现代浏览器几乎全面支持Fetch API的今天,我们是否真的还需要这个第三方HTTP库?

Fetch API自2015年随ES6推出以来,已经发展了近8年时间。根据CanIUse的最新数据,全球浏览器支持率已达到97.12%。即使是需要兼容旧版浏览器的项目,也可以通过简单的polyfill(仅3KB左右)实现支持。相比之下,axios虽然提供了便利的封装,但其核心功能大部分都能被原生API替代。

重要提示:如果你的项目已经深度依赖axios的拦截器、请求取消等高级特性,盲目替换可能会带来额外工作量。但对于新项目或简单请求场景,原生方案确实值得考虑。

2. Fetch API核心功能解析

2.1 基础请求示例对比

先看一个最基本的GET请求实现差异:

// axios版本 axios.get('/api/user') .then(response => console.log(response.data)) .catch(error => console.error(error)); // Fetch版本 fetch('/api/user') .then(response => { if (!response.ok) throw new Error(response.statusText); return response.json(); }) .then(data => console.log(data)) .catch(error => console.error(error));

关键差异点:

  1. Fetch需要手动检查response.ok状态
  2. 响应体需要调用.json()方法解析(对于JSON数据)
  3. 错误处理机制不同(Fetch不会将HTTP错误状态码视为reject)

2.2 请求配置参数对照表

功能需求axios实现Fetch实现
请求方法指定method: 'post'method: 'POST'(需大写)
请求头设置headers: {'X-Token': 'abc'}headers: new Headers({'X-Token': 'abc'})
请求体传参data: {key: 'value'}body: JSON.stringify({key: 'value'})
超时设置timeout: 5000需配合AbortController实现
响应类型responseType: 'json'调用.json()/.text()等方法

2.3 高级功能实现方案

2.3.1 请求取消
const controller = new AbortController(); // 设置超时自动取消 const timeoutId = setTimeout(() => controller.abort(), 5000); fetch('/api/slow', { signal: controller.signal }) .then(response => { clearTimeout(timeoutId); // 处理响应 }) .catch(err => { if (err.name === 'AbortError') { console.log('请求被取消'); } });
2.3.2 拦截器模拟

虽然Fetch没有内置拦截器,但可以通过高阶函数实现类似功能:

const createFetchWithInterceptors = (baseFetch) => { return async (input, init) => { // 请求拦截 const modifiedInit = { ...init, headers: { ...init?.headers, 'X-Request-ID': generateUUID() } }; try { const response = await baseFetch(input, modifiedInit); // 响应拦截 if (response.status === 401) { redirectToLogin(); throw new Error('未授权'); } return response; } catch (error) { // 错误处理 logError(error); throw error; } }; }; const enhancedFetch = createFetchWithInterceptors(fetch);

3. 性能优化与实战技巧

3.1 减少包体积的实际收益

通过webpack-bundle-analyzer分析一个典型项目:

  • 使用axios时:主包体积增加约12KB(gzipped)
  • 改用Fetch后:仅需添加3KB的polyfill(针对IE11等旧浏览器)

对于移动端优先的项目,这9KB的差异可能意味着:

  • 3G网络下加载时间减少约300ms
  • 低端设备解析时间减少约50ms
  • 整体页面评分提升5-10分(Lighthouse)

3.2 常见问题解决方案

3.2.1 默认不带cookie

需要显式设置credentials:

fetch('/api/auth', { credentials: 'include' // 相当于axios的withCredentials: true });
3.2.2 响应超时处理

结合AbortController的完整实现:

async function fetchWithTimeout(url, options = {}, timeout = 8000) { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), timeout); try { const response = await fetch(url, { ...options, signal: controller.signal }); clearTimeout(timer); if (!response.ok) { throw new Error(`${response.status} ${response.statusText}`); } return response; } catch (err) { clearTimeout(timer); if (err.name === 'AbortError') { throw new Error(`请求超时(${timeout}ms)`); } throw err; } }
3.2.3 上传进度监控

通过读取ReadableStream实现:

async function uploadWithProgress(url, file) { const response = await fetch(url, { method: 'POST', body: file, headers: { 'Content-Type': file.type } }); const reader = response.body.getReader(); const contentLength = +response.headers.get('Content-Length'); let receivedLength = 0; while(true) { const {done, value} = await reader.read(); if (done) break; receivedLength += value.length; const percent = Math.round((receivedLength / contentLength) * 100); updateProgress(percent); // 更新UI进度 } }

4. 迁移策略与决策建议

4.1 适合迁移的场景

  1. 新项目启动:没有历史包袱,可以直接采用现代方案
  2. 简单请求场景:仅需基础GET/POST请求
  3. 性能敏感型应用:特别是移动端H5页面
  4. PWA/SSR应用:需要最小化依赖项

4.2 建议保留axios的情况

  1. 复杂拦截器链:如统一认证、错误上报等深度定制
  2. 请求/响应转换:需要自动处理特殊数据格式
  3. 同时兼容Node和浏览器:axios天然支持同构应用
  4. 已有大型代码库:迁移成本可能超过收益

4.3 渐进式迁移方案

对于大型现存项目,可以采用混合模式逐步迁移:

// http.js - 统一出口 export const request = (window.fetch ? fetchWrapper : axios); async function fetchWrapper(input, init) { // 在这里实现与axios兼容的API try { const response = await fetch(input, { ...init, headers: { 'Content-Type': 'application/json', ...init?.headers } }); if (!response.ok) throw new Error(response.statusText); return response.json(); } catch (error) { // 统一错误格式 return { status: error.response?.status || 0, message: error.message }; } }

5. 生态工具推荐

虽然使用原生API,但这些工具可以提升开发体验:

  1. wretch:轻量级Fetch封装(<2KB)

    wretch('/api') .json({data: 'value'}) .post() .json(console.log)
  2. redaxios:兼容axios API的微型替代品(约800字节)

    const axios = redaxios.create({baseURL: '/api'});
  3. ofetch:Nuxt团队开发的智能Fetch工具

    $fetch('/api', { retry: 3, timeout: 5000 });

在实际项目中,我通常会先尝试纯Fetch实现,只有当遇到复杂场景时才考虑引入这些轻量工具。这种渐进式的方案既能保持代码简洁,又能在必要时获得额外功能支持。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询