日常开发优先用axios,简单脚本或现代浏览器轻量需求可用fetch;二者设计目标不同,不可互为替代。fetch默认不带cookie、无超时、4xx/5xx不自动reject,需手动检查response.ok;axios自动处理JSON、错误、超时等,但体积大且不可tree-shake。

直接说结论:日常开发优先用 axios,简单脚本或现代浏览器环境轻量需求可用 fetch;但别把 fetch 当成 axios 的“精简替代”,它们设计目标不同,强行混用容易踩坑。
fetch 默认不带 cookie,且 4xx/5xx 不报错
fetch 的 Response.ok 是判断 HTTP 状态码是否在 200–299 的唯一可靠方式,then 里拿到的响应体不会因 404 或 500 自动 reject —— 这和 axios 默认抛异常的行为完全相反。
常见错误现象:fetch('/api/user').then(res => res.json()) 遇到 401 时仍会执行 res.json(),结果抛出解析空响应体的错误,掩盖了真实状态码问题。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 必须手动检查
response.ok或response.status -
跨域请求需显式传
{ credentials: 'include' }才带 cookie - 没有默认 timeout,超时要靠
AbortController自己控制
axios 自动处理 JSON、错误、超时,但体积大、不可 tree-shake
axios 在请求发出前自动序列化 data(如对象转 JSON),响应时自动 JSON.parse,还内置了 timeout、validateStatus、transformRequest 等实用配置。但它的整个包(约 14KB gzip)无法按需引入 —— 即便只用 get 方法,也会打包全部逻辑。
使用场景:
- 需要统一拦截请求/响应(比如加 token、错误 toast)
- 大量表单提交、文件上传(
FormData支持更稳) - 老项目兼容 IE11(
fetch需 polyfill,axios原生支持)
注意:axios 的 response.data 是已解析的 JS 对象,而 fetch 的 response.json() 是 Promise,这点常被忽略导致类型误判。
不要在 fetch 中直接 await response.json() 而不检查 status
这是最常被复制粘贴却出问题的写法:
const res = await fetch('/api/data');
const data = await res.json(); // ❌ 404 时 res.json() 可能 resolve 一个空对象或抛错
正确做法是先确认状态再解析:
const res = await fetch('/api/data', { credentials: 'include' });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json(); // ✅
如果项目已用 axios,就别在同一个项目里混用 fetch 处理同类接口 —— 错误处理逻辑、取消机制、拦截时机都不一致,后期维护成本陡增。
复杂请求(上传进度、流式响应、自定义 header 兼容性)优先选 axios
fetch 对 ReadableStream 支持较好(适合大文件分块上传或 SSE),但对上传进度监听无原生 API;axios 提供 onUploadProgress 回调,且对 Content-Type 的自动推导更鲁棒(比如传 File 对象时自动设为 multipart/form-data 并生成 boundary)。
容易被忽略的地方:
-
fetch发送FormData时不会自动设置Content-Typeheader,浏览器会自动生成带 boundary 的值,但如果你手动设置了headers: { 'Content-Type': 'multipart/form-data' },反而会破坏上传 -
axios的params是 URL 查询参数,data是请求体,而fetch全靠手拼 URL 和body字段,稍不注意就发错位置
真正需要权衡的不是“哪个更好用”,而是“你的项目是否承担得起额外的 14KB 和运行时开销,以及团队是否愿意统一维护一套请求抽象”。











