fetch()默认不抛出HTTP错误,需手动检查response.ok;POST需JSON.stringify()且匹配Content-Type;跨域带cookie需credentials:'include'和服务端Allow-Credentials响应;重定向需redirect选项控制;超时需AbortController;上传进度仅XHR支持。

fetch() 基本用法和常见报错
直接调用 fetch() 不会自动抛出 HTTP 错误(比如 404、500),这是最常踩的坑。你以为请求失败了,其实只是 response.ok 为 false,但 Promise 依然 resolve。
正确做法是手动检查状态:
fetch('/api/user')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
})
.catch(err => console.error(err));
- 不加
response.ok判断,404也会进.then() -
response.json()本身可能 reject(比如返回空体或非 JSON 内容),要单独捕获 - GET 请求默认不带 credentials,跨域时 cookie 不会发送,需显式加
{ credentials: 'include' }
POST 提交 JSON 数据的写法
很多人漏掉 Content-Type 头或 body 格式不对,导致后端收不到数据。
关键点:body 必须是字符串,且 header 要匹配:
立即学习“前端免费学习笔记(深入)”;
fetch('/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username: 'a', password: 'b' })
});
- 忘记
JSON.stringify()→ 后端收到[object Object] - 写了
Content-Type却传了 FormData → 浏览器自动覆盖 header,实际发的是multipart/form-data - 需要带 cookie 且跨域时,除了
credentials: 'include',服务端还必须返回Access-Control-Allow-Credentials: true
处理重定向和网络异常
fetch() 对网络层失败(如 DNS 失败、连接中断)才 reject;301/302 重定向默认自动跟随,但不会暴露中间响应。
如果需要控制重定向行为(比如登录跳转后取新 URL),用 redirect: 'manual':
fetch('/api/data', { redirect: 'manual' })
.then(response => {
if (response.type === 'opaqueredirect') {
// 被重定向且被浏览器拦截(CORS 场景下)
console.log('Redirect blocked');
}
});
-
redirect: 'error'可让 3xx 状态直接 reject,适合调试重定向逻辑 - 超时需手动实现(
AbortController),原生不支持timeout选项 - 移动端弱网下,
fetch()可能卡住不 reject,建议配合AbortSignal.timeout()(现代浏览器)或自定义定时器
与 XMLHttpRequest 对比的关键差异
不是“哪个更好”,而是“哪里不能互换”:比如上传进度、流式读取、取消请求的粒度。
fetch() 没有上传进度事件,大文件上传无法显示进度条;而 XMLHttpRequest 的 upload.onprogress 是唯一可靠方案。
-
fetch()的ReadableStream支持分块读取响应体,但兼容性差(response.body.getReader()在 Safari 旧版不可用) - 取消请求:fetch 用
AbortController,XHR 用.abort(),行为不同——前者是中断整个 fetch 过程,后者可触发onabort - Cookie 默认策略不同:XHR 默认发 cookie,fetch 默认不发(
credentials: 'same-origin'才等效)
真正麻烦的是混合场景:比如一个页面同时用 fetch 和 XHR,又依赖统一的鉴权头或错误拦截逻辑,这时候得额外封装一层适配。



















