前端API错误码设计为何总在两端扯皮?我的一份建议规范
几乎每个前端团队都经历过这样的场景:联调群里甩出一张截图,接口返回 200,code 是 5001,页面白屏。前端问后端“这个码什么意思”,后端回“文档里有”;前端翻文档,发现文档上写的 5001 是“余额不足”,而这次报的是“活动已结束”。于是一来一回,问题从技术问题变成了态度问题。
扯皮的根源从来不是谁不专业,而是边界没划清。HTTP 状态码、业务错误码、展示文案,这三件事被硬塞进了一个字段里,谁都能解释,谁都不负责。
根源:三重语义被压进同一个字段
一个错误响应其实同时承载了三种完全不同的信息:
- 传输层:这次请求在网络上、协议上是否成功(HTTP status)
- 业务层:这次操作在业务规则上为什么失败(业务码)
- 展示层:这句话要不要给用户看、怎么看(文案与交互)
当后端用 HTTP 200 + code:500 表达业务失败时,监控、网关、重试中间件全部失明;当前端拿到 message: "系统异常" 直接弹 toast 时,用户看到的是开发者的内部语言。三者混用,扯皮就是必然。
五个典型翻车现场
- 一切皆
200,业务失败藏在自己的code里,网关和 APM 无法统计错误率。 message直接透传给用户,出现NullPointerException或者英文堆栈。- 错误码复用且无命名空间,
1001在订单模块是“库存不足”,在用户模块是“未登录”。 - 前端硬编码判断
if (res.code === 40001),后端一改码,前端全量发版。 - 文档漂移:接口加了新码,文档还是三个月前的版本。
建议规范:三层分离,各归其位
| 层 | 定义方 | 消费方 | 示例 |
|---|---|---|---|
| HTTP 状态码 | 网关/框架 | 中间件、监控 | 200 / 400 / 401 / 429 / 500 |
| 业务错误码 | 业务后端 | 前端、SDK | 10201 库存不足 |
| 展示文案 | 后端给默认值,前端可覆写 | 用户 | “该商品暂时缺货” |
原则一句话:**HTTP 状态码只表达传输结果,业务码只表达业务语义,文案只负责展示,三者不互相替代。**
编码规则:分段、定长、可读
建议 6 位字符串:模块(2) + 类型(2) + 序号(2),例如 10-20-01。
类型段可以固定含义:
10参数类(客户端可自查)20认证授权类(需要跳登录或无权限提示)30业务规则类(需要展示具体原因)40依赖类(下游服务、第三方)50系统类(未知,兜底)
全局预留 0 表示成功,1xxxxx 作为通用码(未登录、token 过期、无权限、限流)。码用字符串而非数字,避免 0 与 "0"、前导零、JS 精度这些历史坑。
统一响应体
{
"code": "30201",
"message": "sku 1234 stock insufficient", // 给开发看
"userMessage": "该商品暂时缺货", // 给用户看,可空
"traceId": "a1b2c3d4",
"data": null
}
message 面向排查,允许技术细节;userMessage 面向终端,前端没有覆写需求时直接用;traceId 是排障时双方唯一不用吵架的凭据。
前端只认「可操作性分类」,不认具体码
前端不应该、也没必要理解每一个业务码。它只需要知道这个错该做什么动作:
| 前缀 | 前端动作 |
|---|---|
10xxxx | 表单校验或参数修正提示 |
12xxxx | 跳转登录 / 刷新 token |
13xxxx | 展示后端 userMessage |
14xxxx | 静默重试或降级 |
15xxxx / 未知 | 统一兜底 toast + 埋点上报 |
具体码只在需要特殊交互(比如弹确认框)时例外处理,且必须写进 registry 备注。
单一事实来源与类型生成
维护一份 error-codes.yaml,由它生成三样东西:接口文档、后端枚举、前端 TS 联合类型。
type BizCode = '10001' | '10002' | '30201' | '30202';
这样前端写 switch 时是编译期检查,后端改码时是 CI 报错,而不是线上事故。
变更规则:只增不删不改语义
- 新增码:走新序号,不占用废弃码。
- 废弃码:标
deprecated,保留至少两个大版本。 - 修改语义:禁止。语义变了就是新码。
- 删码:需要跨端评审,不允许单方面操作。
一份最小落地清单
- 业务码与 HTTP 状态码解耦,HTTP 只表达传输结果。
- 错误码注册中心化,文档和类型由它生成。
- 响应体固定包含
code / message / userMessage / traceId。 - 前端按前缀做分类兜底,不硬编码具体码。
- 变更走评审,废弃有过渡期。
扯皮的本质是权责不清,不是能力问题。把“谁定义、谁消费、怎么改”写进规范,两端就不会再为同一个 5001 来回甩截图了。规范不用一次到位,但第一次对齐之后,后面每一次联调都会便宜一点。
转载请注明出处,版权归原作者所有。
正式会员






