4. 业务错误码设计原则:如何定义错误码
错误码这东西,说白了就是给开发者看的“暗号”。你在文档里写“错误码 -1 表示失败”,对接的人只能一头雾水。我见过太多项目,错误码随意乱写,最后排查问题全靠猜。今天咱们聊聊怎么设计一套靠谱的业务错误码。
4.1 错误码的核心结构
一个合格的错误码,应该让看的人一秒定位问题。我习惯的结构是 模块 + 编号 + 含义,三部分缺一不可。
推荐格式:XXX - YYYY - ZZZZ
- 模块前缀(XXX):3~4位字母,代表功能模块。比如
USR表示用户模块,PAY表示支付模块。 - 错误编号(YYYY):4位数字,从 0001 开始递增。奇数留给严重错误,偶数留给警告。
- 含义描述:一段简短、无歧义的中文/英文描述。例如“用户不存在”。
举个我实际用过的例子:USR-1001 - 用户不存在。看到这个码,对接方立马知道是用户模块的问题,编号 1001 代表“不存在”这一具体错误。
4.2 模块划分原则
模块不能太粗,也不能太细。太粗就像把所有错误都扔进一个“通用错误”里,等于没分;太细会导致模块前缀列表膨胀到几十个,反而难记。
| 模块 | 前缀 | 典型错误 |
|---|---|---|
| 用户模块 | USR | 账号冻结、密码错误、手机号格式 |
| 支付模块 | PAY | 余额不足、渠道不可用、重复支付 |
| 订单模块 | ORD | 订单不存在、状态异常、超时取消 |
| 网络请求 | NET | 超时、连接失败、协议错误 |
我在项目中还加过一个 SYS 模块,专门放系统级错误(比如数据库连不上)。这样业务错误码和系统错误码就分清楚了。
4.3 编号设计:区间与含义
编号不要随便从 1 开始排。预留好区间,后续扩展才不会乱。我习惯用千分位划分:
- 1xxx:参数校验错误(必填项缺失、格式错误)
- 2xxx:业务逻辑错误(余额不足、状态冲突)
- 3xxx:权限/认证错误( 过期、无权限)
- 4xxx:资源不存在错误(用户、订单、商品等)
- 5xxx:系统内部错误(数据库异常、第三方接口失败)
避坑指南:我曾经遇到过某个模块的编号区间被打乱的情况,同一个区间既放参数错误又放权限错误。排查时看到错误码,得先查文档才知道属于哪类问题。后来强制规定每个模块必须按区间分配,才彻底解决。
4.4 含义描述怎么写
描述要具体、无歧义。别写“操作失败”,写“支付密码输入错误超过3次,账户已锁定”。我见过最差的写法是 -1: error,简直灾难。
好的例子:
USR-2001 - 手机号已被其他账号绑定PAY-3002 - 该支付渠道当日限额已超ORD-1103 - 订单创建时间必须在当前时间之前
嗯,如果你做的是海外 SDK,描述最好中英文都提供。像 PAY-3002 - Daily limit exceeded for this payment method,这样对接方不用查翻译。
4.5 通用错误码 vs 业务错误码
我把它们分成两类:
| 类型 | 特点 | 示例 |
|---|---|---|
| 通用错误码 | 所有模块共用,范围固定 | NET-0001 网络超时,AUTH-0001 无效 |
| 业务错误码 | 模块私有,随业务变化 | USR-1001 用户不存在,PAY-2003 余额不足 |
通用错误码我建议放在一个公共文档里,业务错误码放在各模块接口文档里。这样改业务时不会影响到公共部分。
个人习惯:我还会给通用错误码预留 0000~0999 作为成功/异常状态码。比如 COM-0000 - Success,COM-0001 - Unknown error。这样所有模块都能引用,不用重复定义。
4.6 错误码的生命周期管理
错误码一旦对外发布,就别轻易删除或重编号。你可能会问:“为什么?” 你想想看,如果上游 SDṀ 缓存了旧的错误码含义,你的系统突然改掉了,排查时就会对不上。
我制定的规则是:
- 新增:在区间尾部追加,不能插入已有编号之间。
- 废弃:标记为“已废弃”,但保留在文档中,防止别人误用。
- 修改含义:原则上不允许。如果实在要变,必须发新版 SDK,并在 changelog 里明确说明。
4.7 错误码设计核心逻辑图
下面这张图概括了整套设计流程:
4.8 给新人的几条实战建议
- 别偷懒:错误码文档单独写,不要只写在代码注释里。对接方不看你的源码。
- 统一管理:用 YAML 或 JSON 维护所有错误码,自动生成 SDK 端的枚举类。我吃过手动维护的亏,两边对不上。
- 留足预留区间:比如
USR-1001~1999留给用户模块,即使第一版只用到了 1005,也别让别的模块来抢。 - 错误码返回值要明确:接口返回的结构里,错误码字段永远是字符串或整型,不要混用类型。
核心总结:好的错误码设计 = 模块清晰 + 编号有含义 + 描述无歧义 + 生命周期受控。能做到这四点,至少能省掉一半的线上排查时间。我见过的所有优秀 SDK,错误码文档必然是一等公民。