← [ BACK_TO_NOTES ]

Axios 错误模型

AxiosError 用 response、request 与 setup/config path 区分“收到非成功响应”“请求已发但未收到响应”“请求在发出前或处理阶段失败”;validateStatus 决定哪些 HTTP 状态进入 rejection,但业务错误契约仍应与 Axios transport error 分层。

#concept #evergreen #network #browser #http #javascript #axios

[!info] related notes

Axios 错误模型

一句话定义

Axios 的错误首先应该按请求生命周期发生在哪一层判断,而不是只看 status code。

最常用三分:

error.response
→ 收到了 HTTP response,但按 validateStatus 被判定为失败

error.request
→ request 已创建/发出,但没有拿到 response

neither
→ setup / config / interceptor / serialization 等阶段失败

AxiosError

Axios rejection 通常得到 AxiosError。

常见字段:

  • message
  • name
  • stack
  • config
  • code
  • status(在适用版本/场景中)
  • request
  • response

其中真正重要的是:

先判断 response 是否存在,再判断 request 是否存在。

1. error.response

说明:

request
→ server / intermediary
→ HTTP response returned
→ Axios classified response as rejection

典型:

  • 400
  • 401
  • 403
  • 404
  • 409
  • 422
  • 500

默认情况下,Axios 通常只把 2xx 视为 fulfilled;具体边界由 validateStatus 决定。

此时可以读取:

error.response.status
error.response.data
error.response.headers

有 response 不等于“网络没问题”

它只能说明 HTTP response 到了 Axios。

仍可能是:

  • 网关错误页;
  • API 业务错误;
  • stale proxy;
  • auth/session 问题;
  • server validation failure。

2. error.request

说明 Axios 已创建/发送请求,但没有获得可用 response。

浏览器环境中 request 常对应 XMLHttpRequest;Node adapter 下可能是 ClientRequest 等底层对象。

常见原因:

  • DNS / connection failure;
  • timeout;
  • connection reset;
  • CORS 导致浏览器不给脚本暴露 response;
  • server 没有返回;
  • request 被中止;
  • proxy/network failure。

所以:

error.request 不等于“服务端一定没收到请求”。

尤其对于非幂等操作:

POST /payments
→ server may have committed
→ response lost
→ client only sees network failure

这时不能盲目自动重试。

3. setup / config path

当:

!error.response
&& !error.request

通常说明失败发生在真正 HTTP response 之前的客户端处理路径。

可能包括:

  • invalid config;
  • interceptor throw;
  • adapter/setup error;
  • request transformation / serialization error;
  • 代码自身抛错。

不要统一包装成“Network Error”。

validateStatus

validateStatus 决定:

哪些 HTTP status 会让 Axios Promise resolve,哪些会 reject。

例如:

axios.get('/resource', {
  validateStatus: status => status < 500,
})

这样 404 也可能进入 fulfilled path。

所以:

HTTP status semantics
≠ Axios Promise fulfilled/rejected semantics

后者受 validateStatus 控制。

Transport Error 与 Business Error

这是最重要的工程边界之一。

例如 API 返回:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "ok": false,
  "code": "INSUFFICIENT_BALANCE"
}

Axios 会认为 HTTP 请求成功。

但业务仍失败。

反过来:

HTTP/1.1 409 Conflict

Axios 默认会 reject,但这可能是业务上完全可预期的 state conflict。

因此应用层应该区分:

transport / HTTP failure
vs
domain / business failure

不要把 AxiosError 当作整个系统的唯一 error model。

Interceptor 的影响

response interceptor 可以:

  • normalize error;
  • refresh token;
  • retry;
  • map API error;
  • 添加 telemetry。

但 interceptor 也可能制造新的错误:

original AxiosError
→ interceptor throws another Error
→ original context lost

因此封装时应保留:

  • original cause;
  • status;
  • request id;
  • API error code;
  • retryability。

Cancellation

用户主动取消:

AbortController
→ request aborted

应该与:

  • timeout;
  • offline;
  • server 500;

区分。

取消通常不是需要用户看到“网络错误”的 failure。

toJSON()

AxiosError 的 toJSON() 可以生成更适合日志序列化的结构。

但日志仍要注意:

  • Authorization;
  • Cookie;
  • request body 中的 secret;
  • PII。

不要把完整 config 无脑上传 telemetry。

推荐处理顺序

catch(error)
→ is AxiosError?
→ cancelled?
→ response?
→ request?
→ setup/client error?
→ map to app error contract
→ decide retry / user message / telemetry

常见误区

所有 catch 都叫网络错误

错误。4xx/5xx、CORS、timeout、业务错误、取消都不是同一类。

error.request = 服务端没收到

不能推出。

status 200 = 业务成功

不能推出。

interceptor 自动 retry 所有请求

非幂等 POST 等操作可能产生重复副作用。

学习检查

  1. error.response 与 error.request 分别证明了什么?
  2. 为什么 error.request 不能推出“服务端没有执行”?
  3. validateStatus 改变的是 HTTP status 还是 Axios Promise semantics?
  4. 为什么业务 error contract 不应该直接等同于 AxiosError?
  5. 取消、timeout、500、409 为什么应该被不同处理?
  6. response interceptor 为什么需要保留 original cause?
  7. 给一个支付 POST 超时场景,解释为什么不能仅凭 Axios network error 自动重试。
创建于 2026/4/7 更新于 2026/9/30
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本