fetch 默认不校验HTTP状态码,404/500视为成功需手动检查res.ok;axios默认将4xx/5xx拒绝但需配置响应拦截器处理;两者上传FormData时均不可手动设置Content-Type头。
fetch 和 axios 都能发请求,但默认行为、错误处理、取消机制完全不同——别直接替换用,否则线上会丢 404 或超时失败不报错。
response.ok
这是最常踩的坑:fetch 只在网络异常(如断网、DNS 失败)时 reject,HTTP 状态码 404、500、401 全部算“成功”,then 里照样进。不检查就直接 res.json(),后面逻辑可能拿不到

if (!res.ok) throw new Error(`${res.status} ${res.statusText}`)
res.headers.get('content-type') 要在 res.clone() 后才能多次读取,否则第二次调用返回 nullAbortController 控制:const controller = new AbortController(); fetch(url, { signal: controller.signal }); setTimeout(() => controller.abort(), 8000);
axios 的 response 对象结构和原生不同,data 在 res.data,状态码在 res.status;它默认对非 2xx 状态码 reject,但这个 reject 会被 axios.interceptors.response.use 拦住——很多人没配拦截器,结果 catch 里拿到的是完整响应对象,不是错误实例。
axios.defaults.timeout = 10000,但单个请求可覆盖:axios.get('/api', { timeout: 5000 })
CancelToken(v0.22+ 已弃用)或 AbortController(推荐):const controller = new AbortController(); axios.get('/api', { signal: controller.signal });
Content-Type: application/json,但传 FormData 时得手动删掉:headers: { 'Content-Type': undefined }
Content-Type: multipart/form-data?错,别设如果用 FormData 构造请求体,fetch 和 axios 都**不能手动设置 Content-Type 头**——浏览器会自动生成带 boundary 的 multipart header,手动设会导致 boundary 缺失,后端解析失败(常见报错:Multipart: Boundary not found)。
fetch('/upload', { method: 'POST', body: formData })(不加 headers)axios.post('/upload', formData, { headers: { 'Content-Type': undefined } })
XMLHttpRequest;axios 可用 onUploadProgress: e => console.log(e.loaded / e.total)
真正难的不是怎么写那几行代码,而是记住哪些行为是“默认隐式发生”的:fetch 不校验 HTTP 状态、axios 自动序列化 JSON、两者对 FormData 的 header 处理逻辑相反……这些点在线上出问题时,日志里几乎不报错,只表现为你收不到数据。
来电咨询