微服务异常必须与固定5位错误码强绑定,采用“1字母+4数字”格式(如B0001),按A/B/C分类归属,编号连续且留空隙;异常类须一对一映射不可变错误码对象,实现IErrorCode接口;分层设计BaseException、BusinessException等四类异常;错误码不暴露给用户,需单独提供国际化user_tip。

微服务架构下,自定义异常必须和错误码强绑定,否则跨服务调用时无法准确定位问题来源、类型和责任方。错误码不是“加个数字”那么简单,它要能支撑排查、监控、告警、前端提示、多团队协作等真实场景。
错误码结构要一眼看懂归属
采用 5 位固定格式:1 位字母 + 4 位数字,例如 B0001、C0123。
- A:用户端问题,如参数缺失、格式错误、支付超时(非系统原因)
- B:本系统内部问题,如业务规则冲突、状态非法、数据库约束失败
- C:第三方依赖问题,如短信网关返回失败、支付渠道回调超时、Redis 连接中断
四位编号从 0001 开始,同类错误连续分配,大类之间留至少 100 号空隙(比如 B0001–B0099 是参数校验,B0200 起是库存相关),方便后续插槽。编号不随模块/版本/团队变动,由统一平台审批后固化。
错误码与异常类要一一映射,不可动态生成
每个业务异常类(如 UserNotFoundException、OrderStockNotEnoughException)必须关联唯一、不可变的错误码对象,而不是在抛出时拼字符串或查 Map。
立即学习“Java免费学习笔记(深入)”;
- 定义统一接口
IErrorCode,含code()和message()方法 - 为每类错误定义具体实现,如
USER_NOT_FOUND extends AbsErrorCode,构造时传入"A404"和"用户不存在" - 异常类中直接持有该错误码实例,避免运行时解析或转换
这样做的好处是:编译期可检查、IDE 可跳转、日志中能直接提取 code 字段、监控系统可按前缀聚合(如所有 C 开头错误自动归为“第三方故障”)。
异常类分层设计,兼顾语义与策略
不能只有一层 BusinessException。应按领域和处理方式分层:
-
基础层:
BaseException,含errorCode、上下文Map<String, Object>、支持 cause 链传递 -
业务层:
BusinessException,用于明确属于业务逻辑错误(如余额不足、权限拒绝) -
系统层:
SystemException,用于框架/中间件/基础设施异常(如 DB 连接池耗尽、线程池满) -
外部层:
ExternalServiceException,专用于封装第三方调用失败,并保留原始响应(如微信支付的err_code)
分层后,网关或全局处理器可按类型做差异化处理:业务异常返回 HTTP 200 + 错误体;系统异常返回 500;外部异常可自动触发降级或重试。
错误码不能直接暴露给用户
错误码(error_code)只对开发、运维、测试可见;面向用户的提示语(user_tip)必须单独提供,且支持国际化和上下文填充。
- 异常类中不要把 message 当作 user_tip 使用;应额外提供
getUserTip()方法 - 例如
ORDER_STOCK_NOT_ENOUGH的 message 是"库存不足,商品ID: {id}",而 user_tip 是"当前商品库存紧张,请稍后再试" - 前端只接收
user_tip,后端日志和监控才记录完整error_code和堆栈
这样既保障用户体验,又守住安全边界——避免把内部结构、参数名、服务名等敏感信息泄露出去。


















