Fetch API 默认不校验HTTP状态码、不携带Cookie,需手动检查response.ok、设置credentials: 'include',且不支持原生上传进度和取消请求。

Fetch API 是现代 JavaScript 中发起网络请求的首选方式,它比传统 XMLHttpRequest(AJAX)更简洁、更符合 Promise 语义,但默认不带 Cookie、不自动处理 4xx/5xx 状态码——这是最容易出错的地方。
fetch() 基本用法和必须处理的两个陷阱
调用 fetch() 返回 Promise,但这个 Promise 只在网络失败(如断网、DNS 错误)时 reject;HTTP 状态码如 404 或 500 仍会 resolve。同时,默认不会携带 Cookie,需显式设置 credentials 选项。
- 必须用
response.ok或response.status手动判断业务成功与否 - 需要显式调用
response.json()、response.text()等方法读取响应体,且每个只能调用一次 - 发送带凭证的请求时,务必加
{ credentials: 'include' },否则后端收不到 Cookie
fetch('/api/user', { credentials: 'include' })
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.then(data => console.log(data))
.catch(err => console.error(err));
与 XMLHttpRequest(AJAX)的关键行为差异
不是“Fetch 更先进所以该淘汰 AJAX”,而是二者在错误边界、默认行为、控制粒度上存在实质性分歧。很多老项目迁移失败,是因为直接把 XMLHttpRequest 的写法“翻译”成 fetch,却忽略了这些点:
-
XMLHttpRequest的onerror会捕获网络错误 + HTTP 错误;fetch的catch只捕获网络错误 -
XMLHttpRequest默认发送 Cookie(取决于同源策略);fetch默认credentials: 'omit' -
XMLHttpRequest支持upload.onprogress;fetch没有原生上传进度支持(需用ReadableStream手动拆包) -
XMLHttpRequest可同步阻塞(已废弃);fetch异步且不可退回到同步
常见需求对应写法:POST、JSON、表单、错误重试
实际开发中,很少只发一个裸 GET。不同场景下,fetch 的配置和后续处理逻辑差异明显:
立即学习“Java免费学习笔记(深入)”;
- POST 提交 JSON:
headers要设'Content-Type': 'application/json',且body必须是字符串(用JSON.stringify()) - 提交表单(
FormData):不用设Content-Type,浏览器会自动设置带 boundary 的 multipart 类型 - 简单重试(如 502/503):可在
catch里判断错误类型,再递归调用或用setTimeout延迟重试 - 取消请求:原生
fetch不支持 abort,必须传入AbortController.signal并在超时或用户离开页面时调用abort()
const controller = new AbortController();
fetch('/api/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id: 123 }),
signal: controller.signal
})
// …
兼容性和 polyfill 注意事项
IE 完全不支持 fetch,Safari 10.1+ 才支持 AbortController。如果项目还需兼容旧环境,不要只引入 whatwg-fetch,它不解决 AbortController 或 Response.clone() 缺失问题。
-
whatwg-fetch可补全基本fetch功能,但不支持signal和流式读取 - 需要 abort 能力时,要么降级为
XMLHttpRequest,要么用abortcontroller-polyfill+ 手动封装 cancel 逻辑 -
Response.body(ReadableStream)在 iOS Safari 16.4 之前无法正常使用,做文件下载或大响应流处理时要检测response.body?.getReader
真正难的不是写对第一行 fetch(),而是记住它不帮你做状态码校验、不帮你带 Cookie、不帮你报上传进度、也不帮你取消——这些“不做什么”,恰恰是日常 Bug 的主要来源。











