fetch 是原生替代 XMLHttpRequest 的现代方案,其设计取舍导致默认不带 cookie、不 reject HTTP 错误、无上传进度、不自动序列化/解析数据,需显式配置 credentials、手动检查 response.ok、用 AbortController 控制超时等。
fetch API 不是“比 AJAX 好”,而是原生替代 XMLHttpRequest 的现代方案;它默认不带 cookie、不自动解析 JSON、不 reject 网络错误——这些不是缺陷,是设计取舍,用错才觉得“不好用”。
这是最常踩的坑:发请求时服务端收不到 session 或登录态,浏览器控制台却没报错。
fetch 默认的 credentials 模式是 'omit',即完全不发 cookie{ credentials: 'include' }(跨域时后端还需配 Access-Control-Allow-Credentials: true)'same-origin' 更安全fetch('/api/user', {
credentials: 'include'
})
很多人以为 404、500 会进 catch,结果发现 then 里 response.ok 是 false,但代码已往下跑了。
fetch 只在网络层彻底失败(如 DNS 错、断网、CORS 被拦)时 rejectresponse.ok === false,需手动检查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 本身不提供上传过程中的字节监听能力。
XMLHttpRequest.upload.onprogress,fetch 没等效 APIReadableStream + TransformStream 手动分块读取并上报进度(Chrome 109+ 支持)XMLHttpRequest 上传;大项目用 axios 或封装好的上传库不是 fetch 不够好,而是它不

data:传对象要自己 JSON.stringify(),还要设 Content-Type: application/json
response.json()
AbortController 配合 signal 实现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 还是用。