如何实现原生JavaScript Fetch API的完整错误处理?
完整处理Fetch API错误的方案
Great question! 我当初把AJAX换成Fetch的时候,也因为它的错误处理逻辑跟AJAX不一样踩过不少坑,刚好可以跟你分享一套完整的错误处理方案,覆盖你提到的所有场景~
首先得明确Fetch的核心特性:Fetch返回的Promise只会在两种情况下reject:
- 真正的网络故障(比如断网、DNS解析失败、禁用网络服务)
- CORS配置错误(浏览器的同源策略限制)
像404、500这类HTTP状态码错误,Fetch会正常resolve一个Response对象,只是这个对象的ok属性会是false——这是新手最容易忽略的点。
完整的错误处理代码示例(async/await版,更易读)
async function fetchData(url) { try { // 发起请求 const response = await fetch(url); // 第一步:处理HTTP状态码错误(4xx/5xx) if (!response.ok) { // 根据不同状态码做针对性处理,也可以直接用默认状态文本 switch(response.status) { case 404: throw new Error('请求的资源不存在(404)'); case 500: throw new Error('服务器内部出错啦(500)'); case 403: throw new Error('没有权限访问该资源(403)'); default: throw new Error(`请求失败,状态码:${response.status}`); } } // 第二步:解析响应数据(根据需求选json/text/blob等) const data = await response.json(); return data; } catch (error) { // 第三步:统一处理所有错误 if (error instanceof TypeError) { // 这类错误对应断网、CORS配置问题,比如你禁用网络服务时会触发 console.error('网络或权限异常:', error.message); // 这里可以给用户友好提示,比如"网络连接失败,请检查网络设置" } else { // 处理我们自定义抛出的HTTP状态码错误 console.error('请求错误:', error.message); } // 可选:把错误抛出去让上层调用者处理,或者返回默认值 throw error; } } // 使用示例 fetchData('https://api.example.com/data') .then(data => console.log('请求成功:', data)) .catch(err => console.log('最终错误捕获:', err));
关键细节解释
- 检查
response.ok:这个属性是Fetch提供的快捷判断方式,等价于response.status >= 200 && response.status < 300,只要状态码不在成功范围内,我们就主动抛出错误。 TypeError捕获:当你禁用网络服务、或者遇到CORS错误时,Fetch会直接抛出TypeError,我们可以在catch块里单独处理这类场景,给用户明确的网络异常提示。- 自定义错误信息:根据不同的HTTP状态码抛出对应错误,能让调试和用户提示更精准。
链式写法版本(如果习惯Promise链式调用)
fetch('https://api.example.com/data') .then(response => { if (!response.ok) { throw new Error(`请求失败:${response.status} ${response.statusText}`); } return response.json(); }) .then(data => console.log('请求成功:', data)) .catch(error => { if (error instanceof TypeError) { console.error('网络/CORS错误:', error); } else { console.error('HTTP错误:', error); } });
额外注意点
- CORS错误的具体细节(比如哪个CORS头配置错了)只能在浏览器控制台看到,前端代码里无法获取这些信息(浏览器的安全限制),所以只能给用户提示“权限异常”。
- 如果不需要区分具体状态码,也可以简化错误抛出逻辑:
if (!response.ok) throw new Error(response.statusText)。
内容的提问来源于stack exchange,提问作者suchislife801




