应根据项目需求选择 Fetch 或 Axios:Fetch 轻量现代但需手动处理错误、超时和取消;Axios 提供拦截器、自动 JSON 解析等便利功能,但增加依赖。关键在统一错误分类与状态管理。

Fetch API 是现代浏览器发起网络请求的原生方案,但直接使用它容易忽略错误处理、超时控制和请求取消等关键问题;Axios 提供了更友好的默认行为和可扩展能力,但引入额外依赖需权衡。是否用 Axios,取决于你是否需要拦截器、自动 JSON 解析、取消请求或 IE 兼容性支持。
Fetch API 的常见陷阱与修复写法
原生 fetch() 不会因 HTTP 状态码(如 404、500)抛出错误,response.ok 必须手动检查;同时它不支持超时,且无法中止正在进行的请求(除非用 AbortController)。
- 忘记检查
response.ok→ 导致 4xx/5xx 响应被当作成功处理 - 没传
signal→ 请求卡死时无法主动中断 - 未设置
Content-Type或credentials→ 登录态丢失或后端拒收
const controller = new AbortController();
setTimeout(() => controller.abort(), 8000);
try {
const res = await fetch('/api/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: 123 }),
signal: controller.signal,
credentials: 'include'
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
} catch (err) {
if (err.name === 'AbortError') console.log('请求已超时或取消');
else console.error('请求失败:', err);
}
Axios 的配置要点与默认行为差异
Axios 默认自动解析 JSON 响应体,但默认不携带 cookies(withCredentials: false),且响应结构是包裹式的 response.data,不是裸数据。它的拦截器非常实用,但要注意:请求拦截器中修改 config.url 后,baseURL 不再生效。
-
axios.defaults.baseURL只影响未以http://开头的 URL - 响应拦截器里抛错,会进入
.catch(),但原始response已不可见 —— 需提前保存 - 取消请求必须用
CancelToken.source()或AbortController(v0.27+)
axios.defaults.withCredentials = true;
axios.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${getToken()}`;
return config;
});
axios.interceptors.response.use(
res => res.data, // 统一提取 data
err => {
if (err.response?.status === 401) logout();
return Promise.reject(err);
}
);
何时该坚持用 Fetch,而非引入 Axios
项目已用 ESM 按需加载、目标环境为现代浏览器(Chrome 62+/Firefox 57+)、团队倾向最小依赖、且不需要请求重试或复杂拦截逻辑时,Fetch 更轻量可控。尤其在 Service Worker 或 Deno 环境中,Axios 并不适用。
立即学习“Java免费学习笔记(深入)”;
- 构建产物大小敏感(Axios gzip 后约 4.5KB,Fetch 零成本)
- 需要精细控制流:比如用
ReadableStream处理大文件分块上传 - 已有封装层(如 SWR、React Query)接管请求逻辑,Axios 的拦截器反而冗余
并发请求与错误聚合的实际处理方式
无论是 Promise.all() 还是 axios.all(),任一请求失败都会导致整个集合 reject。真实场景中往往需要“尽力而为”——即返回所有结果(含错误),而不是中断全部。
- 用
Promise.allSettled()替代Promise.all(),获取每个请求的{ status: 'fulfilled' | 'rejected', value | reason } - Axios 中避免在单个
axios.all()调用里混用不同 base URL 或超时策略 - 对批量 ID 查询,优先考虑服务端聚合接口,而非前端发 N 个请求
const requests = ids.map(id =>
fetch(`/api/user/${id}`).then(r => r.json()).catch(err => ({ error: err.message }))
);
const results = await Promise.allSettled(requests);
const successes = results.filter(r => r.status === 'fulfilled').map(r => r.value);
const failures = results.filter(r => r.status === 'rejected').map(r => r.reason);
真正麻烦的不是选 Fetch 还是 Axios,而是统一错误分类(网络层?业务层?认证失效?)、标准化 loading 状态管理、以及让 timeout 和 abort 行为在 UI 上可感知 —— 这些几乎从不在库文档里写清楚,却直接影响调试效率。











