关键在于从错误源头、响应特征和处理逻辑三层面分离:网络错误(如TypeError、无response)发生在请求传输阶段,业务错误(response存在且status≥400或含自定义code)属服务端明确响应;应结构化判断而非字符串匹配,并依此差异化重试与日志归因。

关键在于从错误源头、响应特征和处理逻辑三个层面做分离,而不是统一用 catch 捕获后模糊处理。
看错误发生的位置:网络层 vs 响应层
网络错误发生在请求发出前或响应未完整到达时;业务错误是服务端明确返回了 HTTP 响应,只是状态或内容不符合预期。
-
网络错误典型表现:fetch 抛出
TypeError(如 "Failed to fetch")、AbortError(超时中断)、Axios 的err.code === 'ECONNABORTED'或err.request存在但err.response为undefined -
业务错误典型表现:响应对象存在(
response.status可读),但status >= 400,或响应体中含code: 4001等自定义业务码;此时response.ok === false,但不是网络断开
用结构化判断代替字符串匹配
不要只靠 err.message.includes('network') 这类脆弱方式。推荐分层检查:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 先检查是否有
response:有 → 进入业务错误分支;无 → 归为网络/传输层错误 - 有响应时再看
status:4xx 多为客户端问题(参数错、权限不足),一般不重试;5xx 中的 503/504 可重试,500 视服务端日志决定 - 解析响应体后检查
data.code:如code === 10002表示“库存不足”,属于明确业务拒绝,不应重试
在重试逻辑里明确过滤条件
重试不是对所有失败一视同仁。应在发起下一次重试前做判定:
立即学习“Java免费学习笔记(深入)”;
- 允许重试的情况:
TypeError、AbortError、status === 0(fetch 断连)、status === 503 || status === 504 - 禁止重试的情况:
status === 400 || 401 || 403 || 404、自定义code === 20001(参数校验失败)、response.headers.get('x-retryable') === 'false'(服务端显式声明不可重试) - 可选策略:对 500 做白名单判断,比如仅当
response.statusText === 'Internal Server Error'且无error_id时才重试,避免掩盖真实 bug
上报与调试时保留区分痕迹
日志埋点字段要体现差异,方便后续归因:
- 网络错误日志加
"error_type": "network",附带err.name和底层原因(如"cause": "TypeError") - 业务错误日志用
"error_type": "business",带上status、data.code、data.message - 前端监控平台可据此统计“网络失败率”和“业务失败率”,两者趋势不同说明问题域不同

















