Fetch API 是浏览器原生网络请求接口,基于 Promise 设计,不自动处理 HTTP 错误;4xx/5xx 状态码不会触发 reject,需手动检查 response.ok 或 status。
Fetch API 是浏览器原生提供的、用于发起网络请求的现代 JavaScript 接口;它不是 XMLHttpRequest 的升级版,而是设计哲学完全不同的替代方案——默认基于 Promise,不自动处理 HTTP 错误状态码,也不共享 cookie(除非显式配置)。
这是最常踩的坑:用 fetch() 请求一个返回 404 的 URL,then() 依然会执行,因为只要网络层通了、响应头收到了,Promise 就算 fulfilled。你得手动检查 response.ok 或 response.status。
fetch('/api/user/999')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
})
.catch(err => console.error(err));
response.ok 等价于 response.status >= 200 && response.status
XMLHttpRequest 在 4xx/5xx 时不会
触发 onerror,但会进 onload,同样需要手动判断 status
上传大文件或需要实时显示下载进度时,XMLHttpRequest 的 upload.onprogress 和 download.onprogress 仍是不可替代的。Fetch 没有等效机制;虽可用 AbortController 中止整个请求,但无法在流式读取过程中暂停或监听已接收字节数。
fetch() 支持 signal 参数配合 AbortController 实现超时或取消,但仅作用于请求发起阶段或未开始读取时XMLHttpRequest,或用 ReadableStream + tee() 自行分块读取(复杂且不兼容旧浏览器)response.body.getReader() 逐段处理,但无内置进度百分比默认情况下,fetch() 不发送 cookies,也不携带认证头(如 Authorization),即使目标域名与当前页面同源。这和 XMLHttpRequest 的默认行为一致,但开发者常常忽略这点,导致登录态丢失。
fetch('/api/profile', {
credentials: 'include' // 必须显式声明
});
credentials: 'include':发送 cookies 和认证头(需服务端设置 Access-Control-Allow-Credentials: true)credentials: 'same-origin':默认值,只在同源时发(但很多人误以为是“自动同源”)credentials: 'omit':从不发送(类似 XMLHttpRequest.withCredentials = false)XMLHttpRequest 的 withCredentials 默认为 false,行为其实一致,只是 Fetch 的默认值名更易误导真正难处理的不是语法差异,而是 Fetch 把错误分类、凭据策略、流控制这些原本隐含在 XHR 里的行为全部暴露成显式配置项——写对容易,写全、写稳、覆盖边界场景,反而更费神。