fetch 是原生替代 XMLHttpRequest 的现代方案,其设计取舍导致默认不带 cookie、不 reject HTTP 错误、无上传进度、不自动序列化/解析数据,需显式配置 credentials、手动检查 response.ok、用 AbortController 控制超时等。

fetch API 不是“比 AJAX 好”,而是原生替代 XMLHttpRequest 的现代方案;它默认不带 cookie、不自动解析 JSON、不 reject 网络错误——这些不是缺陷,是设计取舍,用错才觉得“不好用”。
为什么 fetch 不会自动带上 cookie
这是最常踩的坑:发请求时服务端收不到 session 或登录态,浏览器控制台却没报错。
-
fetch默认的credentials模式是'omit',即完全不发 cookie - 要发 cookie,必须显式写
{ credentials: 'include' }(跨域时后端还需配Access-Control-Allow-Credentials: true) - 如果只对同域请求需要 cookie,用
'same-origin'更安全
fetch('/api/user', {
credentials: 'include'
})
fetch 返回 Promise 却不 reject 网络失败
很多人以为 404、500 会进 catch,结果发现 then 里 response.ok 是 false,但代码已往下跑了。
-
fetch只在网络层彻底失败(如 DNS 错、断网、CORS 被拦)时 reject - HTTP 状态码 4xx/5xx 仍算“成功响应”,
response.ok === false,需手动检查 - 建议封装一层:遇到非 2xx 状态码主动
throw new Error()
fetch('/api/data')
.then(r => {
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return r.json();
})
.catch(err => console.error(err));
fetch 没有 progress 回调,上传大文件怎么办
如果要做上传进度条,fetch 本身不提供上传过程中的字节监听能力。
立即学习“Java免费学习笔记(深入)”;
- 浏览器原生支持的是
XMLHttpRequest.upload.onprogress,fetch没等效 API - 可行解:用
ReadableStream+TransformStream手动分块读取并上报进度(Chrome 109+ 支持) - 更现实的做法:小项目继续用
XMLHttpRequest上传;大项目用axios或封装好的上传库
和 jQuery.ajax 相比,fetch 缺少哪些“方便但隐式”的行为
不是 fetch 不够好,而是它不替你做判断:
- 不自动序列化
data:传对象要自己JSON.stringify(),还要设Content-Type: application/json - 不自动解析响应体:即使后端返回 JSON,也要显式调
response.json() - 不支持超时:需用
AbortController配合signal实现 - 不合并 headers:多次 set 同个 header 会覆盖,不是追加
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
fetch('/api/long', {
signal: controller.signal
}).catch(err => {
if (err.name === 'AbortError') console.log('timeout');
});
真正难的不是写 fetch,是理解它不帮你兜底——每个环节都得自己声明意图。习惯后反而更可控;想省事就别硬套,该用 axios 还是用。











