axios 请求只报泛化 Network Error:如何为网络错误分类并输出详细原因
【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios
axios 默认对大量不同的网络故障抛出同一个"Network Error"消息:断网、DNS 解析失败、服务器拒绝连接、CORS 拦截、请求超时,在catch里看起来几乎一样,调试时无法区分根因。本场景的目标是:在 axios 上挂一个响应拦截器,对错误做分类,给每个错误对象重写error.code(如ERR_TIMEOUT、ERR_DNS_FAILURE)并新增一个error.detailedMessage字段输出可读原因。仓库中的examples/improved-network-errors.md与examples/network_enhanced.js提供了完整的方案与实现,按浏览器和 Node.js 两种环境均可使用。
前提只需安装 axios:
npm install axios先弄清:为什么 axios 只报泛化错误
查阅 官方错误处理文档 的错误码表,与网络故障相关的有两个关键点:
ERR_NETWORK:网络类问题。在浏览器中,这个错误还可能由 CORS 或 Mixed Content 策略违规引起。文档明确指出:浏览器不允许 JS 代码澄清由安全问题引起的错误真实原因,需要自行查看控制台。- 超时默认报
ECONNABORTED;只有设置transitional.clarifyTimeoutError: true后才会报ETIMEDOUT,这样超时错误才能和其他中断区分开。
也就是说,axios 本身的错误对象信息有限(浏览器安全限制决定了这一点),要输出详细原因,需要在业务层基于error.code、error.message和响应状态码做二次分类。
方案:响应拦截器 + 错误增强函数
examples/improved-network-errors.md 描述的机制:
- 用
axios.create(config)创建实例; - 通过
client.interceptors.response.use()注册响应拦截器,在拒绝分支里捕获错误(拦截器机制见 Interceptors 文档); - 拦截器调用
enhanceNetworkError(error):根据error.code、error.message、error.response.status判断错误类型,改写error.code,挂上新字段error.detailedMessage,然后重新throw出去。
完整实现见仓库中的 examples/network_enhanced.js,核心代码如下:
import axios from 'axios'; function enhanceNetworkError(error) { // when Offline (no internet) if (typeof navigator !== 'undefined' && !navigator.onLine) { error.code = 'ERR_NO_INTERNET'; error.detailedMessage = 'No internet connection detected. Please check your connection and try again.'; } // when DNS failure occurs (invalid domain) else if (error.code === 'ENOTFOUND' || /dns/i.test(error.message)) { error.code = 'ERR_DNS_FAILURE'; error.detailedMessage = 'Unable to reach the requested domain. Please verify the URL or your network settings.'; } // when Connection refused by server else if (error.code === 'ECONNREFUSED' || /refused/i.test(error.message)) { error.code = 'ERR_CONNECTION_REFUSED'; error.detailedMessage = 'Connection was refused by the server. It may be temporarily unavailable.'; } // when Request timeout happens else if (error.code === 'ETIMEDOUT' || /timeout/i.test(error.message)) { error.code = 'ERR_TIMEOUT'; error.detailedMessage = 'The request took too long to respond. Please try again later.'; } // when CORS restriction happens (for browser only) else if (/CORS/i.test(error.message)) { error.code = 'ERR_CORS_BLOCKED'; error.detailedMessage = 'The request was blocked due to cross-origin restrictions.'; } // when Server-side error occurs else if (error.response && error.response.status >= 500) { error.code = 'ERR_SERVER'; error.detailedMessage = 'A server-side issue occurred. Please try again later.'; } // when Client-side error occurs else if (error.response && error.response.status >= 400) { error.code = 'ERR_CLIENT'; error.detailedMessage = 'A client-side error occurred. Please check your request.'; } // when unknown network issue occurs else { error.code = 'ERR_NETWORK_GENERIC'; error.detailedMessage = 'A network issue occurred. Please check your connection or try again later.'; } return error; } export function createEnhancedClient(config = {}) { const client = axios.create(config); client.interceptors.response.use( (response) => response, (error) => { throw enhanceNetworkError(error); } ); return client; } export default enhanceNetworkError;分类规则按if/else链的先后顺序匹配(先命中先归类):
| 判断条件 | 归类 code | detailedMessage 含义 |
|---|---|---|
navigator.onLine为false(浏览器) | ERR_NO_INTERNET | 无网络连接 |
error.code === 'ENOTFOUND'或 message 含dns | ERR_DNS_FAILURE | 域名无法解析 |
error.code === 'ECONNREFUSED'或 message 含refused | ERR_CONNECTION_REFUSED | 服务器拒绝连接 |
error.code === 'ETIMEDOUT'或 message 含timeout | ERR_TIMEOUT | 请求超时 |
message 含CORS(浏览器) | ERR_CORS_BLOCKED | 跨域被拦截 |
error.response.status >= 500 | ERR_SERVER | 服务端错误 |
error.response.status >= 400 | ERR_CLIENT | 客户端错误 |
| 以上都不满足 | ERR_NETWORK_GENERIC | 未识别的网络问题 |
注意 5xx 的判断在 4xx 之前,因此 500 以上归类为ERR_SERVER,400–499 归类为ERR_CLIENT。
使用与验证
用createEnhancedClient()创建客户端即可,之后所有请求的错误都会带上分类信息。以下示例中的baseURL是文档示例值,替换为你自己的接口地址:
const api = createEnhancedClient({ baseURL: 'https://example.com' }); api .get('/data') .then((res) => console.log(res.data)) .catch((err) => { console.error(err.code); // e.g., ERR_TIMEOUT console.error(err.detailedMessage); // e.g., "The request took too long to respond." });验证方式:发起一个必然失败的请求(超时、错误域名、断网均可),在catch中打印err.code和err.detailedMessage,能按上表输出对应分类即说明拦截器生效。上面代码块中的两个// e.g.,值是文档给出的示例输出,不是固定预期。
若想在分类前先检查 axios 原始错误,错误处理文档 给出了三分支判断:error.response存在表示服务器已响应但状态码不在 2xx 范围;error.request存在表示请求已发出但没有收到响应(浏览器中是XMLHttpRequest实例,Node.js 中是http.ClientRequest实例);两者都没有则是请求设置阶段出错。错误对象还支持error.toJSON()获取完整信息,含message、name、stack、config、code、status字段。
让超时错误可靠命中超时分支
enhanceNetworkError的超时分支依赖ETIMEDOUT(或 message 含timeout)。而 axios 默认超时报的是ECONNABORTED。按 官方超时处理文档,应在请求配置(或createEnhancedClient传入的 config)中设置timeout并开启clarifyTimeoutError:
const response = await axios.get("https://example.com/data", { timeout: 5000, // 5 seconds transitional: { // set to true if you prefer ETIMEDOUT over ECONNABORTED clarifyTimeoutError: true, }, });官方文档同时提示:生产环境应始终设置timeout,否则卡住的请求可能无限挂起。clarifyTimeoutError的含义与默认值(false)见 request-config 文档。
限制与边界
- 浏览器中的 CORS/Mixed Content 无法可靠识别:官方文档明确说明浏览器不允许 JS 代码澄清这类安全错误的真实原因,要定位需查看控制台。
/CORS/i.test(error.message)这条规则只在错误 message 中确实含有CORS字样时才命中,不能保证覆盖所有跨域失败。 - 离线检测只在浏览器生效:
ERR_NO_INTERNET分支依赖navigator.onLine,Node.js 环境中该分支不成立,断网会落到后续规则或ERR_NETWORK_GENERIC。 - 分类顺序固定:
if/else链保证先命中的规则优先(如离线判断在 DNS 判断之前),不要随意调整顺序。 - 该方案是业务层封装:它改写的是你应用持有的错误对象,axios 抛出的原始错误(
ERR_NETWORK、ECONNABORTED等)行为不变,其他使用 axios 的模块不受此拦截器影响。
参考文件
- examples/improved-network-errors.md:问题描述、分类映射与用法示例
- examples/network_enhanced.js:
enhanceNetworkError与createEnhancedClient完整实现 - docs/pages/advanced/error-handling.md:axios 官方错误结构、错误码表与超时处理
- docs/pages/advanced/interceptors.md:拦截器机制与执行顺序
- docs/pages/advanced/request-config.md:
timeout、transitional.clarifyTimeoutError配置说明
【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考