news 2026/9/5 19:49:34

Axios 错误处理深度解析:AxiosError 结构、错误码、超时区分与敏感信息脱敏

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Axios 错误处理深度解析:AxiosError 结构、错误码、超时区分与敏感信息脱敏

Axios 错误处理深度解析:AxiosError 结构、错误码、超时区分与敏感信息脱敏

【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios

axios 默认在请求失败时让 Promise 被 reject,而失败的具体形态由AxiosError对象承载。本文基于官方文档docs/fr/pages/advanced/error-handling.md并结合 axios 源码,完整解析 axios 抛出的错误结构(messagecodestatusconfigrequestresponse等字段)、axios 内部识别的全部错误码及其在源码中的产生位置,以及validateStatus自定义判定、timeout超时错误区分(ECONNABORTEDETIMEDOUT)、畸形 HTTP(S) URL 的严格校验,还有通过toJSON()序列化错误和使用redact配置避免密钥泄漏的实战方案。读完本文,你可以在浏览器与 Node.js 环境下编写结构清晰、可区分超时/网络/取消等错误类型、且不会在日志中泄露凭据的错误处理代码。

AxiosError:axios 错误的统一载体

axios 抛出的绝大多数错误都是AxiosError实例(由原生Error派生),文档给出的通用结构如下:

属性定义
message错误消息与失败状态码的简短摘要。
name标识错误来源。来自 axios 的错误,该值始终为AxiosError
stack提供错误的调用堆栈。
config请求发起时 axios 的配置对象,包含用户为请求/实例设置的各项配置。
code代表被 axios 识别的错误类型,具体取值见下一节的错误码表。
statusHTTP 响应状态码。

此外,AxiosError实例还带有一个布尔标记isAxiosError = true,这正是axios.isAxiosError(error)的判定依据。从源码看,isAxiosError.js 中该函数只做一次属性检查:

export default function isAxiosError(payload) { return utils.isObject(payload) && payload.isAxiosError === true; }

而在 AxiosError.js 的构造函数中,各字段被显式挂到实例上(第 160–168 行):

this.name = 'AxiosError'; this.isAxiosError = true; code && (this.code = code); config && (this.config = config); request && (this.request = request); if (response) { this.response = response; this.status = response.status; }

可以据此推断出文档中三个错误分支与源码字段的对应关系:只有拿到服务端响应(response)时才设置status;只有请求已发出但无响应时request才有值;而配置阶段的错误通常既没有request也没有response,只留下configmessage

axios 内部识别的错误码(code)

文档列出了 axios 可识别的全部错误码。这些错误码以静态属性形式定义在 AxiosError.js 中,可统一通过AxiosError.ERR_NETWORK等引用:

错误码含义
ERR_BAD_OPTION_VALUEaxios 配置中提供了无效或不受支持的值。
ERR_BAD_OPTIONaxios 配置中提供了无效的选项。
ECONNABORTED通常表示请求超时(除非设置了transitional.clarifyTimeoutError),或被浏览器/插件中止。
ETIMEDOUT请求超过了 axios 默认超时时间。需将transitional.clarifyTimeoutError设为true,否则抛出的仍是通用的ECONNABORTED
ERR_NETWORK网络类问题。在浏览器中,CORS 违规或混合内容(mixed content)也可能导致此错误;出于安全考虑,浏览器不允许 JS 得知真实原因,请查看控制台。
ERR_FR_TOO_MANY_REDIRECTS请求被重定向的次数超过了 axios 配置中指定的最大值。
ERR_DEPRECATED使用了 axios 中已被弃用的功能或方法。
ERR_BAD_RESPONSE响应无法被正确解析或格式不符合预期,通常对应5xx状态码。
ERR_BAD_REQUEST请求格式不符合预期或缺少必需参数,通常对应4xx状态码。
ERR_CANCELED功能或方法被用户通过 AbortSignal(或 CancelToken)显式取消。
ERR_NOT_SUPPORT当前 axios 运行环境不支持该功能或方法。
ERR_INVALID_URLaxios 请求提供了无效的 URL。
ERR_FORM_DATA_DEPTH_EXCEEDED序列化params或表单数据时,某对象深度超过了配置的maxDepth,默认限制 100 层。可参考 请求配置文档 中的paramsSerializerformSerializer说明。

源码中可以找到几个代表性错误码的产生点:

  • ERR_BAD_REQUEST/ERR_BAD_RESPONSE由 settle.js 在响应判定失败时抛出,状态码 4xx/5xx 与错误码的对应关系即在此处确定:
reject(new AxiosError( 'Request failed with status code ' + response.status, response.status >= 400 && response.status < 500 ? AxiosError.ERR_BAD_REQUEST : AxiosError.ERR_BAD_RESPONSE, response.config, response.request, response ));
  • ERR_INVALID_URL由 buildFullPath.js 中的assertValidHttpProtocolURL抛出(详见下文"畸形 URL"一节),此外 fromDataURI.js 在解析非法 data URI 时也会使用该错误码。
  • ERR_FORM_DATA_DEPTH_EXCEEDED分别由 toFormData.js 与 formDataToJSON.js 在递归序列化超过maxDepth时抛出。

捕获与处理错误:response / request / config 三分支

axios 的默认行为是:请求失败时 reject Promise。捕获错误后,推荐的判断顺序是"先查error.response,再查error.request,最后处理配置阶段的错误"。这是文档给出的标准示例:

axios.get("/user/12345").catch(function (error) { if (error.response) { // 请求已发出,且服务端返回了非 2xx 的状态码 console.log(error.response.data); console.log(error.response.status); console.log(error.response.headers); } else if (error.request) { // 请求已发出,但未收到任何响应 // 浏览器中 `error.request` 是 XMLHttpRequest 实例, // Node.js 中是 http.ClientRequest 实例 console.log(error.request); } else { // 请求配置阶段就发生了错误 console.log("Error", error.message); } console.log(error.config); });

这个三分支结构之所以可靠,是因为它直接对应AxiosError构造函数的赋值逻辑:response分支意味着响应已存在(服务端返回了非 2xx);request分支意味着请求已挂到实例上但响应缺失(网络中断、超时、CORS 等);否则就是配置校验、URL 解析等问题,此时只有configmessage可用。在 Node.js 环境中,http.js 适配器抛错时会把原生http.ClientRequest作为request传入;浏览器中则由 xhr.js 传入XMLHttpRequest实例。

使用 validateStatus 自定义"何为失败"

axios 的默认判定是status >= 200 && status < 300时 resolve,否则 reject。通过配置项validateStatus可以覆盖这一条件,自行决定哪些 HTTP 状态码应当触发错误:

axios.get("/user/12345", { validateStatus: function (status) { return status < 500; // 只有状态码小于 500 才视为成功 }, });

默认实现在 defaults/index.js 中定义,判定逻辑则在 settle.js 执行:若validateStatus(response.status)返回真值则 resolve,否则构造AxiosError并 reject。此外 mergeConfig.js 中还有一个transitional.validateStatusUndefinedResolves细节:当请求级配置显式传入validateStatus: undefined且该过渡开关为false时,会回退到实例级validateStatus,这允许你用请求级配置覆盖实例默认值。

处理超时:ECONNABORTED 与 ETIMEDOUT 的区分

当请求超过配置的timeout时,axios 默认以ECONNABORTED拒绝 Promise。若希望获得更精确的ETIMEDOUT错误码,需要设置transitional.clarifyTimeoutError: true

async function fetchWithTimeout() { try { const response = await axios.get("https://example.com/data", { timeout: 5000, // 5 秒 transitional: { // 若希望用 ETIMEDOUT 替代 ECONNABORTED,设为 true clarifyTimeoutError: true, }, }); console.log("Response:", response.data); } catch (error) { if (axios.isAxiosError(error)) { if (error.code === "ECONNABORTED" || error.code === "ETIMEDOUT") { console.error("Request timed out. Please try again."); return; } console.error("Axios error:", error.message); return; } console.error("Unexpected error:", error); } }

源码层面,transitional.js 显示clarifyTimeoutError的默认值是false,因此不显式开启时超时一律是ECONNABORTED。浏览器适配器的request.ontimeout处理(xhr.js)体现了这一切换逻辑:

reject( new AxiosError( timeoutErrorMessage, transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED, config, request ) );

Node.js 适配器 http.js 中的超时处理采用完全相同的三元表达式;另外 composeSignals.js 在组合 AbortSignal 超时时直接抛出ETIMEDOUT,可据此推断不同触发路径下错误码可能略有差异,编写兜底逻辑时建议同时兼容ECONNABORTEDETIMEDOUT

生产环境务必设置timeout,否则被阻塞的请求可能永远处于挂起状态。相关配置项参见 请求配置文档 中的timeouttransitional.clarifyTimeoutError说明。

畸形 HTTP(S) URL:ERR_INVALID_URL 的严格校验

axios 会拒绝urlbaseURL中协议后缺少//http:/https:URL。例如https:example.comhttps:/example.com不会被浏览器或 Node.js 的 URL 解析器"静默修正",而是直接抛出codeERR_INVALID_URLAxiosError。请使用https://example.com这类格式正确的 URL。

错误消息会明确指出有问题的 URL,例如:

Invalid URL "https:example.com": missing "//" after protocol

这一行为在 buildFullPath.js 中实现,核心是一个正则与断言函数:

const malformedHttpProtocol = /^https?:(?!\/\/)/i; function assertValidHttpProtocolURL(url, config) { if (typeof url === 'string') { const normalizedURL = normalizeURLForProtocolCheck(url); if (malformedHttpProtocol.test(normalizedURL)) { throw new AxiosError( `Invalid URL ${JSON.stringify(redactSensitiveURLParts(normalizedURL))}: missing "//" after protocol`, AxiosError.ERR_INVALID_URL, config ); } } }

其中 normalizeURLForProtocolCheck.js 会先对齐 WHATWG URL 的预处理规则:剔除前导空白字符并移除\t\n\r控制字符后再做协议检查,防止通过控制字符绕过校验。

安全动机:这种严格校验能阻止畸形 URL 绕过baseURL拼接逻辑或 URL 白名单机制。更重要的是,错误消息中对 URL 的展示做了系统性脱敏(redactSensitiveURLParts):

  • 保留协议、主机、路径与查询参数名,使请求仍可被识别;
  • 掩码凭据(userinfo)、查询参数值与 fragment 内容,替换为[REDACTED ****]标记。

之所以必须"系统性"掩码,是因为AxiosError.message总是被toJSON()原样序列化进日志,而配置中的redact选项只能清理config下的键值,无法清理已经生成好的错误消息文本。单元测试 buildFullPath.test.js 验证了这一行为,例如:

'Invalid URL "https:[REDACTED ****]@api.example.com/v1?apikey=[REDACTED ****]&id=[REDACTED ****]#token=[REDACTED ****]&[REDACTED ****]": missing "//" after protocol'

序列化错误:toJSON() 与 redact 脱敏配置

使用toJSON()可以获得包含更多信息的错误对象快照:

axios.get("/user/12345").catch(function (error) { console.log(error.toJSON()); });

从 AxiosError.js 的toJSON()实现可以看到,返回对象包含标准字段(messagenamestack)、浏览器扩展字段(descriptionfileName等)以及 axios 特有字段(configcodestatus)。

为了避免把密钥从error.config中打进日志,可以在请求配置里传入redact数组。调用AxiosError#toJSON()时,任何深度的、大小写不敏感的同名配置键都会被替换为脱敏标记:

axios.get("/user/12345", { headers: { Authorization: "Bearer token" }, redact: ["authorization"] }).catch(function (error) { console.log(error.toJSON().config.headers.Authorization); // [REDACTED ****] });

实现上,toJSON()检测到config.redact是非空数组时,会调用redactConfig(AxiosError.js)生成脱敏后的配置快照:它把redact中的键统一转为小写后逐一匹配,递归遍历普通对象与数组,对AxiosHeaders实例先调用其toJSON()再处理,并通过seen列表短路循环引用。命中键的值被替换为模块级常量REDACTED = '[REDACTED ****]'。AxiosError.test.js 的toJSON redaction via config.redact测试组覆盖了完整语义:redact未定义或为空数组时保持旧序列化行为;顶层键、嵌套对象(auth.passwordproxy.auth.password)、AxiosHeaders实例、对象数组内的键均可被正确掩码;并且对继承的redact访问器与原型污染场景做了防护。

小结:可落地的错误处理清单

结合文档与源码,可归纳出如下可复制的错误处理实践:

  1. axios.isAxiosError(error)确认错误来源,再按error.responseerror.request→ 其他 的顺序三分支处理;
  2. 依赖error.code而非error.message文本做类型分发:ERR_CANCELED(取消)、ETIMEDOUT/ECONNABORTED(超时)、ERR_NETWORK(网络/CORS)、ERR_BAD_REQUEST/ERR_BAD_RESPONSE(4xx/5xx);
  3. validateStatus精确控制哪些状态码算失败,例如把 404 视为"正常空结果"时返回status < 500
  4. 生产环境设置timeout,并按需开启transitional.clarifyTimeoutError以获得可区分的ETIMEDOUT
  5. 日志输出统一走error.toJSON(),并对Authorizationtokenpassword等键配置redact;注意错误消息文本本身的脱敏只由 axios 在生成时完成(如畸形 URL 场景),redact无法回溯清理。

【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 19:44:35

SG90 360°连续旋转舵机控制方法:用writeMicroseconds实现方向与转速

很多人第一次买 SG90 舵机时&#xff0c;会看到两个版本在货架上并排出现&#xff1a;标准 180 舵机和 360 连续旋转舵机。如果你买的是后者&#xff0c;又习惯性地用 write(90) 想让它转到一个固定角度&#xff0c;很快就会发现问题&#xff1a;舵机要么上电就朝一个方向猛转…

作者头像 李华
网站建设 2026/9/5 19:43:33

别再盲目重铅远投!野钓线组与竿坠搭配的实用思路

不少新手刚接触钓鱼时&#xff0c;很容易形成一个固定思路&#xff1a;竿子要够重够硬&#xff0c;铅坠也要重&#xff0c;线越粗越好&#xff0c;因为只有这样才能把饵打到水中间去&#xff0c;打得远才钓得到鱼。这个想法不能说完全没道理&#xff0c;但它把“够得着鱼”和“…

作者头像 李华
网站建设 2026/9/5 19:43:27

AI编程实测:Codex与Zcode的核心差距,不在模型而在Agent工作流

把 DeepSeek V4 Pro Zcode 和 Codex 放到同一个测试桌面上&#xff0c;任务定为“复刻一个饥荒风格的小游戏”&#xff0c;是我最近做得最有意思的一次实验。做之前我以为最值得关注的&#xff0c;是这几套组合里谁能一次性写出看起来更完整的代码。结果真正让我印象深刻的&am…

作者头像 李华