错误码设计原则:常见格式规范、分段含义与版本演化
错误码设计这活儿,说难不难,说简单也不简单。我在项目中见过太多“拍脑袋”定出来的错误码——1001 代表什么?没人记得住。后来新同学接盘,两眼一抹黑,对着 error log 直骂娘。
今天咱们聊聊设计错误码时应该遵循的几个基本原则。说白了,就是让错误码既能读、又能查、还能跟着版本一起长大。
2.1 常见格式规范:给错误码定个“长相”
我个人的习惯是,错误码至少包含两个维度:错误来源 和 错误类型。比如 HTTP API 里常见的 400 Bad Request,来源是客户端,类型是参数问题。
但 SDK 内部错误码比 HTTP 状态码复杂得多。你想想看,同一个网络错误,在 iOS 端、Android 端、服务端可能表示方式完全不同。所以我建议采用 分段式编码,把错误码拆成几个明确的部分。
推荐格式:
[平台标识][模块编号][错误类型][具体原因]
举个例子:
1-0201-003:1 代表 iOS 平台;02 代表登录模块;01 代表网络超时类型;003 代表具体超时场景。- 也可以简化为
I_LOGIN_TIMEOUT_003,用枚举字符串 + 数字后缀。
2.2 分段含义:每段都是有故事的
我早期在做一个即时通讯 SDK 时,错误码直接用了四位数字:1001、1002……后来版本迭代到 3.0,新增了十几类错误,数字早就不够用了。拆段之后才彻底解放了。
下面这张图概括了分段错误码的结构和演化关系——
分段的具体含义我一般这样定:
- 平台标识(1位数字或字母):比如 1=Android、2=iOS、3=Server、4=Web。虽然 SDK 通常只跑在一个平台,但文档里混在一起时能快速定位。
- 模块编号(2位数字):01=初始化、02=登录、03=消息、04=推送……按照功能域划分,未来扩展时 +10 跳号预留。
- 错误类型(2位数字):01=超时、02=参数校验、03=授权失败、04=资源不足、05=服务器拒绝……
- 具体原因(3位数字):这个数字只在模块内部定义,可以由后端 SDK 团队自由使用。
你可能会问:“为什么不直接用英文单词?” 我试过,但跨语言环境时英文单词可能被国际化截断。数字是通用的。
2.3 版本演化:错误码也得“长个儿”
SDK 有版本,错误码自然也有生命周期。我记得有一次,一个老版本 SDK 上报了 4000 错误码,运维同学翻遍文档没找到。后来发现那是 v1.0 的“设备被踢出群”,到了 v2.0 改成了 3-02-03-001,旧码没做兼容。
那之后我定了个规矩:
- 错误码一旦发布,永不可删除——只可废弃(deprecated),不可销毁。
- 每个大版本都要维护一张“映射表”——旧码 → 新码 = 一段映射逻辑。
- 废弃码时加上新版本提示——例如
WARN: 错误码 1001 已废弃,请迁移至 1-01-02-000。
小技巧: 在 SDK 内部可以维护一个 legacy_map 字典,运行时自动转换。调用方代码不用改,只调整日志和监控。
2.4 避坑指南:我曾经踩过的三个坑
- 不要用无意义的自增数字。我曾经直接
ERR_1、ERR_2、……,后来排查问题时根本不知道 57 是什么。一定要加分段含义。 - 不要频繁重排模块编号。排序一旦发布,就把它当作固定 ID。我在项目里见过某同事把“消息模块”从 03 改成 05,导致所有旧日志查询全部失效。
- 不要忘记预留跳号。模块编号按 10 的倍数预留:01、11、21……这样中间插入新模块时不用改后面。
特别提醒: 如果你在写多平台 SDK,错误码的枚举定义文件一定要从同一个源(比如 JSON 或 YAML)生成。我曾经手写 iOS 和 Android 两份枚举,结果一个平台多了一个码,排查两天才发现不对等。
2.5 推荐的分段格式参数对比
下面是我整理的不同分段方案,供你参考选择:
| 方案 | 示例 | 优点 | 缺点 |
|---|---|---|---|
| 纯数字分段 | 1-02-01-003 | 跨语言无歧义;可大规模排序 | 可读性稍差 |
| 字母前缀 + 数字 | A02C01S003 | 紧凑;一人码视觉识别快 | 大小写易混;分类数量有限 |
| 枚举字符串 + 编号 | IOS_LOGIN_TIMEOUT_003 | 自解释;开发人员友好 | 字符串太长;国际化时翻译困难 |
| UUID 分组(不推荐) | err_abc123de | 唯一性极强 | 无法分类查找,日志分析噩梦 |
我目前最常用的是第一种——纯数字分段。它结构清晰,配合一份错误码文档,团队上手极快。你如果团队规模不大,用枚举字符串也行,但一定要统一命名风格。
小结
错误码设计的核心就三条:
- 分段:把平台、模块、类型、原因分离开。
- 稳定:发布即不可删,版本演进时只映射不覆盖。
- 可查:每个错误码都必须能通过逻辑推导出大概含义,而不是全靠背。
这章我们就聊到这。下次写代码定义错误码时,记得先画个分段表格再说。