response.json() 报错主因是未正确处理其返回的 Promise,需用 await 或 .then();同时须检查 response.ok、加 try/catch 捕获异常,并注意 CORS、超时等常见问题。

Fetch 发起 GET 请求时为什么 response.json() 会报错
常见错误是直接把 response.json() 当作同步函数用,比如写成 const data = response.json(),结果得到一个 Promise 而不是解析后的对象。这是因为 json() 方法本身返回的是 Promise,必须用 await 或 .then() 处理。
正确做法是确保在 async 函数中使用 await response.json(),或链式调用 .then(res => res.json())。
- 没加
await就读取data.name→ 报Cannot read property 'name' of undefined - 忘记检查
response.ok→ 404、500 响应仍会执行.json(),但后端可能返回 HTML 错误页,导致Unexpected token - 没加
try/catch→ 网络中断、CORS 拒绝、JSON 格式错误都会抛出异常,不捕获就会静默失败
最简可用的 fetch + JSON 处理模板
以下是最小可运行结构,覆盖状态判断、JSON 解析和错误捕获:
async function fetchUserData() {
try {
const response = await fetch('/api/user');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data);
return data;
} catch (err) {
console.error('Fetch failed:', err.message);
throw err;
}
}
这个模板里几个关键点:
-
fetch()默认就是 GET,无需显式传method: 'GET' -
response.ok判断的是状态码是否在 200–299 范围,比手动写response.status === 200更安全 - 两次
await:一次等网络响应,一次等 JSON 解析完成 —— 它们是两个独立异步阶段 - 错误统一由
catch捕获,包括网络层(如 DNS 失败)、HTTP 层(如 401)、解析层(如非法 JSON)
遇到 CORS 被拒或预检失败怎么办
如果控制台报 No 'Access-Control-Allow-Origin' header 或 Response to preflight request doesn't pass access control check,说明后端没配 CORS,前端 fetch 无法绕过。
此时不能靠改前端代码解决,但可以快速验证问题来源:
- 用
curl -v https://example.com/api/data直接请求,看响应头是否含Access-Control-Allow-Origin - 如果是本地开发,用
mode: 'no-cors'会让请求发出去但禁止读响应 —— 这不是解决方案,只是调试手段 - 开发时临时用代理(如 Vite 的
server.proxy或 Webpack 的devServer.proxy)把请求转到同源后端,避开浏览器 CORS 检查 - 后端需设置响应头:
Access-Control-Allow-Origin: *(简单场景)或指定域名;若带凭证(cookie),则不能用*,必须明确写域名且加Access-Control-Allow-Credentials: true
需要手动设置 Accept 头或超时怎么办
默认情况下 fetch() 会自动加 Accept: */*,但某些 API 要求明确声明 Accept: application/json 才返回 JSON;另外原生 fetch 不支持 timeout,得自己封装。
示例:带自定义头和手动超时控制
async function fetchWithTimeout(url, options = {}, timeout = 5000) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...options,
headers: {
'Accept': 'application/json',
...options.headers
},
signal: controller.signal
});
clearTimeout(id);
return response;
} catch (err) {
clearTimeout(id);
if (err.name === 'AbortError') throw new Error('Request timed out');
throw err;
}
}
注意点:
-
AbortController是现代浏览器标准 API,IE 不支持;如需兼容,得用setTimeout + Promise.race模拟 -
Accept头不是所有接口都需要,但像 Rails、Spring Boot 默认配置下,加了更稳妥 - 不要在
headers里设Content-Type或Content-Length—— GET 请求没有请求体,这些头会被浏览器忽略甚至报错
实际用的时候,最常漏掉的是 response.ok 检查和外层 try/catch,这两个一缺,错误就藏在控制台里不动声色。











