fetch 发 GET 请求需 await fetch() 后调用 await res.json();POST 要匹配 body 与 Content-Type;超时/取消需 AbortController;跨域问题源于预检失败或 CORS 响应头缺失。

fetch 基本用法:发个 GET 请求别漏掉 await 和 .json()
fetch 默认不自动解析响应体,直接 await fetch(url) 拿到的是一个 Response 对象,不是 JSON 数据。常见错误是忘了调用 .json() 或 .text(),结果打印出来是 [object Promise] 或控制台报错 TypeError: Failed to execute 'json' on 'Response': body stream is locked。
正确写法示例:
async function getData() {
const res = await fetch('/api/user');
if (!res.ok) throw new Error(`HTTP error! status: ${res.status}`);
const data = await res.json(); // 必须 await 这一步
return data;
}
-
fetch()返回 Promise,必须用await或.then()处理 -
res.ok判断 HTTP 状态是否在 200–299 范围,404、500不会自动 reject -
.json()本身也返回 Promise,不能省略await - 如果后端返回的是纯文本或 HTML,改用
res.text();二进制用res.arrayBuffer()
POST 请求怎么传数据?body 和 headers 别配错
fetch 发 POST 时,Content-Type 和 body 格式必须匹配,否则后端收不到字段。最常踩的坑是:传了 JSON.stringify(obj) 却没设 headers: {'Content-Type': 'application/json'},或者反过来,用 FormData 却写了 application/json。
常见组合:
立即学习“Java免费学习笔记(深入)”;
// JSON 数据(推荐 API 场景)
fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: 'a@b.c', password: '123' })
});
// 表单数据(上传文件或兼容传统后端)
const form = new FormData();
form.append('file', fileInput.files[0]);
fetch('/upload', {
method: 'POST',
body: form // 此时不要设 Content-Type,浏览器会自动生成带 boundary 的 multipart
});
-
FormData实例直接当body,不要手动设Content-Type,否则会破坏 boundary -
JSON.stringify()后的字符串是string类型,不是对象,别漏掉这步 - GET 请求不能有
body,参数只能拼在 URL 后或用URLSearchParams
fetch 无法 abort 或 timeout?得靠 AbortController
fetch 本身不支持超时或手动取消,长时间 pending 会卡住 UI。原生方案是用 AbortController,但要注意:它只中断网络请求,不会自动清理 Promise,且 abort() 后再 await 会抛 AbortError。
function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
return fetch(url, { signal: controller.signal })
.finally(() => clearTimeout(id));
}
// 使用
fetchWithTimeout('/slow-api')
.then(r => r.json())
.catch(err => {
if (err.name === 'AbortError') console.log('请求超时');
});
-
signal选项必须显式传入fetch配置,否则无效 -
AbortController是一次性对象,每次请求都要新建实例 - 超时逻辑需自己用
setTimeout+clearTimeout配合,fetch 无内置 timeout 参数 - 某些旧版 Safari 不支持
AbortController,需检查兼容性或用 polyfill
跨域失败时,浏览器控制台只显示 "Failed to fetch"?先看预检和 CORS 响应头
fetch 遇到跨域且服务端未正确配置 CORS 时,控制台通常只报 TypeError: Failed to fetch,没有具体原因。这是因为浏览器在发出实际请求前会先发 OPTIONS 预检,如果预检失败(如缺少 Access-Control-Allow-Origin),整个请求就被拦在网关外,fetch 拿不到任何响应。
排查步骤:
- 打开 DevTools → Network → 找到对应请求 → 查看 Headers 标签页,确认响应头含
Access-Control-Allow-Origin: *或指定域名 - 如果有自定义 header(如
Authorization)或非简单方法(PUT、DELETE),必须确保服务端同时返回Access-Control-Allow-Headers和Access-Control-Allow-Methods -
前端加
credentials: 'include'时,后端Access-Control-Allow-Origin不能为*,必须写明确域名 - 本地开发常用代理绕过 CORS(如 Vite 的
server.proxy或 Webpack 的devServer.proxy),而非在代码里硬加mode: 'no-cors'(它禁用 JS 读响应,基本没用)
fetch 的行为很“干净”,但也因此把很多底层细节(比如预检、流锁、header 匹配)推给了开发者判断——真正难的不是调用,而是看清请求到底卡在哪一层。











