fetch 不抛出 HTTP 错误,仅网络完全失败时 reject;需手动检查 response.ok 或 status 并显式 throw,且 res.json() 必须 await 并在同 try 块中捕获,超时需 AbortController,错误应分类处理。

Fetch 本身不抛出网络错误,try...catch 捕获不到 404、500 或断网
这是最常被误解的一点:fetch() 只有在**网络完全失败**(如 DNS 解析失败、请求被阻止、离线)时才 reject;而 HTTP 状态码如 404、500 仍会 resolve,只是返回一个 Response 对象。所以直接 try...catch 包裹 fetch() 调用,对服务端报错毫无作用。
正确做法是:先 await fetch(),再手动检查 response.ok 或 response.status,显式抛错:
try {
const res = await fetch('/api/data');
if (!res.ok) {
throw new Error(`HTTP error: ${res.status} ${res.statusText}`);
}
const data = await res.json();
console.log(data);
} catch (err) {
// 这里能捕获:网络中断、跨域拒绝、JSON 解析失败、上面 throw 的错误
console.error(err.message);
}
res.json() 失败会抛 SyntaxError,必须在 try 内部 catch
Response.json() 是异步操作,且只要响应体不是合法 JSON 就会 reject —— 比如后端返回了 HTML 错误页、空响应、或字段类型错乱(如字符串当数字解析)。这个 reject 不会被外层 try...catch 自动捕获,除非你把它也 await 并放在同一 try 块里。
常见错误写法(res.json() 错误逃逸):
立即学习“前端免费学习笔记(深入)”;
try {
const res = await fetch('/api/data');
if (!res.ok) throw new Error(...);
res.json().then(data => ...); // ❌ 异步链脱离 try 范围
} catch (err) { ... }
正确写法(全部 await + 同一 try):
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 始终
await res.json(),不要用.then() - 如果后端可能返回非 JSON(如
text/plain),改用res.text()再手动解析 - 必要时加
try...catch嵌套,只包JSON.parse()(当你用res.text()后手动 parse)
超时控制不能靠 try...catch,得用 AbortController
原生 fetch() 没有 timeout 参数,网络卡住时既不 reject 也不 resolve,try...catch 完全无效。必须配合 AbortController 主动中断:
const controller = new AbortController();
setTimeout(() => controller.abort(), 8000);
try {
const res = await fetch('/api/data', {
signal: controller.signal
});
if (!res.ok) throw new Error(...);
const data = await res.json();
} catch (err) {
if (err.name === 'AbortError') {
console.error('Request timed out');
} else if (err.name === 'TypeError' && err.message.includes('fetch')) {
console.error('Network failed');
} else {
console.error('Other error:', err.message);
}
}
注意:AbortError 是标准名称,但某些环境(如旧版 Safari)可能抛 DOMException,需兼容判断 err.name === 'AbortError' || err.code === 20。
错误分类处理比统一 console.error 更实用
真实项目里,不同错误要走不同逻辑:用户提示、重试、跳转登录页、上报监控。别把所有 catch 都塞进一个 console.error。
建议按来源分三类处理:
-
网络层失败(
TypeError,消息含'fetch'或'network')→ 提示“网络异常,请检查连接” -
HTTP 状态异常(
res.ok === false)→ 根据status做细分:401 跳登录,403 提示无权限,5xx 显示服务异常 -
数据解析失败(
SyntaxError或自定义校验失败)→ 上报格式错误,降级显示默认内容或空状态
实际代码中,这些分支往往需要组合判断,比如 err instanceof SyntaxError 比检查 err.name 更可靠;而 res.status 必须在 fetch() 成功后才能读取——顺序不能错。


















