Fetch API 默认不因 HTTP 错误状态码抛出异常,需手动检查 response.ok 并配合 async/await 显式抛错,才能统一捕获网络错误与业务错误;推荐封装 fetchWithOk 函数提前校验状态并附带调试信息。

Fetch API 默认不会因 HTTP 状态码(如 404、500)抛出错误,所以仅靠 try/catch 捕获不到业务层面的失败响应。要真正拦截网络错误,必须手动检查 response.ok(即 status 是否在 200–299 范围内),再配合 async/await 实现清晰的错误处理流程。
用 async/await 包裹 fetch,再显式判断 response.ok
fetch() 本身返回 Promise,天然适配 async/await;但它的 resolve 值是 Response 对象,不是响应体数据,也不代表请求“成功”。你需要:
- 先
await fetch(...)得到Response - 立刻检查
if (!response.ok),手动抛错(如throw new Error(...)) - 再调用
response.json()或其他解析方法获取数据
这样 try/catch 才能捕获状态码异常和网络异常(如断网、CORS)。
常见错误写法:漏掉 response.ok 判断
下面代码看似用了 async/await,但 404 或 500 响应仍会进入 then 分支,导致后续解析失败或静默错误:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
async function badExample() {
try {
const res = await fetch('/api/user'); // 404 时 res.ok === false,但不会 throw
const data = await res.json(); // 可能报错:Unexpected end of JSON input(空响应体)
return data;
} catch (err) {
console.error(err); // 这里只捕获网络中断、跨域等底层错误
}
}
推荐写法:统一校验 + 自定义错误信息
把状态码检查提前,并附带状态文本和 URL,便于调试:
async function fetchWithOk(url, options = {}) {
const res = await fetch(url, options);
if (!res.ok) {
const error = new Error(`HTTP ${res.status} ${res.statusText}`);
error.status = res.status;
error.url = url;
throw error;
}
return res;
}
// 使用示例
async function getUser(id) {
try {
const res = await fetchWithOk(`/api/users/${id}`);
return await res.json();
} catch (err) {
if (err.status === 404) {
console.warn('用户不存在');
} else if (err.status >= 500) {
console.error('服务端异常,请稍后重试');
} else {
console.error('请求失败:', err.message);
}
throw err;
}
}
补充:区分网络错误与业务错误
fetch() 的 catch 只捕获网络层失败(DNS 失败、连接超时、CORS 阻止等);而 response.ok === false 属于 HTTP 协议层的“业务失败”。两者都应处理,但语义不同:
- 网络错误:通常重试或提示“网络不可用”
- 4xx 错误:多数是客户端问题(参数错、权限不足),不建议重试
- 5xx 错误:服务端问题,可考虑有限重试或降级
因此完整结构应同时覆盖 try/catch(网络异常)和 !res.ok(HTTP 异常)。

















