fetch和axios默认行为差异大:fetch不带cookie、4xx/5xx不reject、需手动检查res.ok并设credentials: 'include';axios自动reject异常但默认也不带cookie,需withCredentials: true;取消机制、超时、文件上传等均不同,混用易致静默失败。

fetch 和 axios 都能发请求,但默认行为、错误处理、取消机制完全不同——别直接替换用,否则线上会静默失败。
fetch 默认不带 cookie,401/403 错误不会自动 reject
fetch 的 response.ok 只判断 HTTP 状态码是否在 200–299,401、403、500 都算“成功”返回,必须手动检查:
fetch('/api/user', {
credentials: 'include' // 不加这行,带 cookie 的接口必 401
})
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.catch(err => console.error(err)); // 这里才真正捕获认证失败
-
credentials: 'include'必须显式声明,否则跨域请求不带 cookie - 网络中断、DNS 失败等底层错误才会进
catch;服务端返回 4xx/5xx 仍走then - 没有内置超时,需用
AbortController手动控制
axios 自动抛出 4xx/5xx 错误,但默认不发 cookie
axios 把 401 当作异常直接进 catch,更符合直觉,但默认仍不携带 cookie:
axios.get('/api/user', {
withCredentials: true // 注意:不是 credentials,是 withCredentials
})
.catch(err => {
if (err.response?.status === 401) {
// 这里能稳定捕获登录过期
}
});
-
withCredentials: true是 axios 的写法,和 fetch 的credentials不兼容 -
err.response存响应体,err.request存原生 XMLHttpRequest 实例 - axios 0.27+ 支持
signal(同 AbortController),老版本只能靠CancelToken(已弃用)
上传文件时,fetch 要手动构造 FormData,axios 会自动处理
传 File 或 Blob 时,fetch 必须显式包装,axios 则直接传对象即可:
立即学习“Java免费学习笔记(深入)”;
// fetch:必须自己 new FormData()
const formData = new FormData();
formData.append('file', fileInput.files[0]);
fetch('/upload', {
method: 'POST',
body: formData // 不能加 headers: {'Content-Type': 'multipart/form-data'},浏览器会自设 boundary
});
// axios:直接传对象,它内部转 FormData
axios.post('/upload', { file: fileInput.files[0] });
- fetch 加了手动
Content-Type头反而会破坏 boundary,导致后端解析失败 - axios 在非
multipart/form-data场景下(如 JSON)仍默认加Content-Type: application/json - 大文件上传进度监听:fetch 用
upload.onprogress,axios 用onUploadProgress配置项
取消请求的写法差异极大,别混用 AbortController 和 CancelToken
现代浏览器中,fetch 用 AbortController 是标准方案;axios 从 0.27 开始也支持它,但旧项目可能还在用已废弃的 CancelToken:
// fetch 标准取消
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal });
controller.abort(); // 立即触发 TypeError: cancelled
// axios 新写法(推荐)
const controller = new AbortController();
axios.get('/api/data', { signal: controller.signal });
controller.abort();
// axios 旧写法(避免新增)
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/api/data', { cancelToken: source.token });
source.cancel(); // 触发 Cancel 错误
- 两种 cancel 机制互不兼容,
AbortController的 error 是DOMException,CancelToken是Cancel实例 - React 中清理副作用时,务必在组件卸载前调用
abort(),否则可能触发内存泄漏警告 - 多个并发请求共用一个
AbortController时,abort 会一并取消全部
真正麻烦的是混合场景:比如用 fetch 封装的工具函数里忘了加 credentials: 'include',又在 axios 请求里漏了 withCredentials: true,两边都拿不到 session,但错误表现一模一样——全是 401,还查不出为什么。











