一、说明

异常的捕获和抛出是软件开发过程中经常需要处理的场景,在传统单体服务中,我们通过统一异常码值的方式可以达到统一异常管理的目的。在微服务体系中,服务非常多,每个服务都需要自己的异常码值,编码体系不断的扩张和越发混乱的问题,变成了软件工程师头痛的事情。

今天通过调研,发现了两种基于阿里巴巴开发规约实现的异常编码体系,包含了具体的编码规则和异常抛出的方式方法。希望对于相同问题感到困惑的朋友有所帮助。

二、阿里巴巴异常规范说明

2.1 基础异常BaseException

作为头部的互联网大厂,阿里巴巴推出的开发手册里对异常编码有完整的表述。里面定义了异常分为三大类

  • 第一种是用户端操作的异常,错误编码前缀A。即用户端操作的异常信息,用户行为紧密相关
  • 第二种是当前系统业务逻辑出错,错误编码前缀B。即其他类型的业务系统异常。
  • 第三种是第三方系统调用出错,错误编码前缀C。即当前系统调用外部系统时发生异常。

另外全部正常是返回五个零“00000”代表SUCCESS,错误时禁止返回

推荐使用正确的分类,但不必要过分纠结当前一场属于A还是B,异常体系只要清晰,能够快速定位异常发生的位置即可。

2.2 扩展异常体系

在上述三大类基础上,扩展了如下的编码体系,可以涵盖所有的错误码。

三、spring工程中如何引入异常编码体系

这里提供了两种方式,一种是单个文件管理所有异常, 第二种是分布式的方式管理异常体系。推荐第二种方式,请大家对比选择性采纳吧。

3.1 单体引入全量错误编码

简单粗暴,将所有的错误编码放在一个文件中。
如果项目需要新的异常,只需要增加新的类别,然后在异常抛出时制定即可

在使用时引入枚举类,抛出异常。
缺点:

  1. 单个文件不断膨胀,所有错误码在一起查找困难
  2. 分布式下维护一个更新频繁的共同文件困难。

编码来源博客

我在生产重新编码了一套命名更规范的,不能copy出来,大家参考这个吧

public enum AliErrorCodeEnum {/*** 成功*/SUCCESS("00000", "一切 ok"),/*** 一级宏观错误码*/USER_ERROR_0001("A0001", "用户端错误"),/*** 二级宏观错误码*/USER_ERROR_A0100("A0100", "用户注册错误"),USER_ERROR_A0101("A0101", "用户未同意隐私协议"),USER_ERROR_A0102("A0102", "注册国家或地区受限"),USER_ERROR_A0110("A0110", "用户名校验失败"),USER_ERROR_A0111("A0111", "用户名已存在"),USER_ERROR_A0112("A0112", "用户名包含敏感词"),USER_ERROR_A0113("A0113", "用户名包含特殊字符"),USER_ERROR_A0120("A0120", "密码校验失败"),USER_ERROR_A0121("A0121", "密码长度不够"),USER_ERROR_A0122("A0122", "密码强度不够"),USER_ERROR_A0130("A0130", "校验码输入错误"),USER_ERROR_A0131("A0131", "短信校验码输入错误"),USER_ERROR_A0132("A0132", "邮件校验码输入错误"),USER_ERROR_A0133("A0133", "语音校验码输入错误"),USER_ERROR_A0140("A0140", "用户证件异常"),USER_ERROR_A0141("A0141", "用户证件类型未选择"),USER_ERROR_A0142("A0142", "大陆身份证编号校验非法"),USER_ERROR_A0143("A0143", "护照编号校验非法"),USER_ERROR_A0144("A0144", "军官证编号校验非法"),USER_ERROR_A0150("A0150", "用户基本信息校验失败"),USER_ERROR_A0151("A0151", "手机格式校验失败"),USER_ERROR_A0152("A0152", "地址格式校验失败"),USER_ERROR_A0153("A0153", "邮箱格式校验失败"),/*** 二级宏观错误码*/USER_ERROR_A0200("A0200", "用户登录异常"),USER_ERROR_A0201("A0201", "用户账户不存在"),USER_ERROR_A0202("A0202", "用户账户被冻结"),USER_ERROR_A0203("A0203", "用户账户已作废"),USER_ERROR_A0210("A0210", "用户密码错误"),USER_ERROR_A0211("A0211", "用户输入密码错误次数超限"),USER_ERROR_A0220("A0220", "用户身份校验失败"),USER_ERROR_A0221("A0221", "用户指纹识别失败"),USER_ERROR_A0222("A0222", "用户面容识别失败"),USER_ERROR_A0223("A0223", "用户未获得第三方登录授权"),USER_ERROR_A0230("A0230", "用户登录已过期"),USER_ERROR_A0240("A0240", "用户验证码错误"),USER_ERROR_A0241("A0241", "用户验证码尝试次数超限"),/*** 二级宏观错误码*/USER_ERROR_A0300("A0300", "访问权限异常"),USER_ERROR_A0301("A0301", "访问未授权"),USER_ERROR_A0302("A0302", "正在授权中"),USER_ERROR_A0303("A0303", "用户授权申请被拒绝"),USER_ERROR_A0310("A0310", "因访问对象隐私设置被拦截"),USER_ERROR_A0311("A0311", "授权已过期"),USER_ERROR_A0312("A0312", "无权限使用 API"),USER_ERROR_A0320("A0320", "用户访问被拦截"),USER_ERROR_A0321("A0321", "黑名单用户"),USER_ERROR_A0322("A0322", "账号被冻结"),USER_ERROR_A0323("A0323", "非法 IP 地址"),USER_ERROR_A0324("A0324", "网关访问受限"),USER_ERROR_A0325("A0325", "地域黑名单"),USER_ERROR_A0330("A0330", "服务已欠费"),USER_ERROR_A0340("A0340", "用户签名异常"),USER_ERROR_A0341("A0341", "RSA 签名错误"),/*** 二级宏观错误码*/USER_ERROR_A0400("A0400", "用户请求参数错误"),USER_ERROR_A0401("A0401", "包含非法恶意跳转链接"),USER_ERROR_A0402("A0402", "无效的用户输入"),USER_ERROR_A0410("A0410", "请求必填参数为空"),USER_ERROR_A0411("A0411", "用户订单号为空"),USER_ERROR_A0412("A0412", "订购数量为空"),USER_ERROR_A0413("A0413", "缺少时间戳参数"),USER_ERROR_A0414("A0414", "非法的时间戳参数"),USER_ERROR_A0420("A0420", "请求参数值超出允许的范围"),USER_ERROR_A0421("A0421", "参数格式不匹配"),USER_ERROR_A0422("A0422", "地址不在服务范围"),USER_ERROR_A0423("A0423", "时间不在服务范围"),USER_ERROR_A0424("A0424", "金额超出限制"),USER_ERROR_A0425("A0425", "数量超出限制"),USER_ERROR_A0426("A0426", "请求批量处理总个数超出限制"),USER_ERROR_A0427("A0427", "请求 JSON 解析失败"),USER_ERROR_A0430("A0430", "用户输入内容非法"),USER_ERROR_A0431("A0431", "包含违禁敏感词"),USER_ERROR_A0432("A0432", "图片包含违禁信息"),USER_ERROR_A0433("A0433", "文件侵犯版权"),USER_ERROR_A0440("A0440", "用户操作异常"),USER_ERROR_A0441("A0441", "用户支付超时"),USER_ERROR_A0442("A0442", "确认订单超时"),USER_ERROR_A0443("A0443", "订单已关闭"),/*** 二级宏观错误码*/USER_ERROR_A0500("A0500", "用户请求服务异常"),USER_ERROR_A0501("A0501", "请求次数超出限制"),USER_ERROR_A0502("A0502", "请求并发数超出限制"),USER_ERROR_A0503("A0503", "用户操作请等待"),USER_ERROR_A0504("A0504", "WebSocket 连接异常"),USER_ERROR_A0505("A0505", "WebSocket 连接断开"),USER_ERROR_A0506("A0506", "用户重复请求"),/*** 二级宏观错误码*/USER_ERROR_A0600("A0600", "用户资源异常"),USER_ERROR_A0601("A0601", "账户余额不足"),USER_ERROR_A0602("A0602", "用户磁盘空间不足"),USER_ERROR_A0603("A0603", "用户内存空间不足"),USER_ERROR_A0604("A0604", "用户 OSS 容量不足"),/*** 例如:每天抽奖数*/USER_ERROR_A0605("A0605", "用户配额已用光"),/*** 二级宏观错误码*/USER_ERROR_A0700("A0700", "用户上传文件异常"),USER_ERROR_A0701("A0701", "用户上传文件类型不匹配"),USER_ERROR_A0702("A0702", "用户上传文件太大"),USER_ERROR_A0703("A0703", "用户上传图片太大"),USER_ERROR_A0704("A0704", "用户上传视频太大"),USER_ERROR_A0705("A0705", "用户上传压缩文件太大"),/*** 二级宏观错误码*/USER_ERROR_A0800("A0800", "用户当前版本异常"),USER_ERROR_A0801("A0801", "用户安装版本与系统不匹配"),USER_ERROR_A0802("A0802", "用户安装版本过低"),USER_ERROR_A0803("A0803", "用户安装版本过高"),USER_ERROR_A0804("A0804", "用户安装版本已过期"),USER_ERROR_A0805("A0805", "用户 API 请求版本不匹配"),USER_ERROR_A0806("A0806", "用户 API 请求版本过高"),USER_ERROR_A0807("A0807", "用户 API 请求版本过低"),/*** 二级宏观错误码*/USER_ERROR_A0900("A0900", "用户隐私未授权"),USER_ERROR_A0901("A0901", "用户隐私未签署"),USER_ERROR_A0902("A0902", "用户摄像头未授权"),USER_ERROR_A0903("A0903", "用户相机未授权"),USER_ERROR_A0904("A0904", "用户图片库未授权"),USER_ERROR_A0905("A0905", "用户文件未授权"),USER_ERROR_A0906("A0906", "用户位置信息未授权"),USER_ERROR_A0907("A0907", "用户通讯录未授权"),/*** 二级宏观错误码*/USER_ERROR_A1000("A1000", "用户设备异常"),USER_ERROR_A1001("A1001", "用户相机异常"),USER_ERROR_A1002("A1002", "用户麦克风异常"),USER_ERROR_A1003("A1003", "用户听筒异常"),USER_ERROR_A1004("A1004", "用户扬声器异常"),USER_ERROR_A1005("A1005", "用户 GPS 定位异常"),/*** 系统异常* 一级宏观错误码*/SYSTEM_ERROR_B0001("B0001", "系统执行出错"),/*** 二级宏观错误码*/SYSTEM_ERROR_B0100("B0100", "系统执行超时"),SYSTEM_ERROR_B0101("B0101", "系统订单处理超时"),/*** 二级宏观错误码*/SYSTEM_ERROR_B0200("B0200", "系统容灾功能被触发"),SYSTEM_ERROR_B0210("B0210", "系统限流"),SYSTEM_ERROR_B0220("B0220", "系统功能降级"),/*** 二级宏观错误码*/SYSTEM_ERROR_B0300("B0300", "系统资源异常"),SYSTEM_ERROR_B0310("B0310", "系统资源耗尽"),SYSTEM_ERROR_B0311("B0311", "系统磁盘空间耗尽"),SYSTEM_ERROR_B0312("B0312", "系统内存耗尽"),SYSTEM_ERROR_B0313("B0313", "文件句柄耗尽"),SYSTEM_ERROR_B0314("B0314", "系统连接池耗尽"),SYSTEM_ERROR_B0315("B0315", "系统线程池耗尽"),SYSTEM_ERROR_B0320("B0320", "系统资源访问异常"),SYSTEM_ERROR_B0321("B0321", "系统读取磁盘文件失败"),/*** 调用第三方服务* 一级宏观错误码*/SERVICE_ERROR_C0001("C0001", "调用第三方服务出错"),/*** 二级宏观错误码*/SERVICE_ERROR_C0100("C0100", "中间件服务出错"),SERVICE_ERROR_C0110("C0110", "RPC 服务出错"),SERVICE_ERROR_C0111("C0111", "RPC 服务未找到"),SERVICE_ERROR_C0112("C0112", "RPC 服务未注册"),SERVICE_ERROR_C0113("C0113", "接口不存在"),SERVICE_ERROR_C0120("C0120", "消息服务出错"),SERVICE_ERROR_C0121("C0121", "消息投递出错"),SERVICE_ERROR_C0122("C0122", "消息消费出错"),SERVICE_ERROR_C0123("C0123", "消息订阅出错"),SERVICE_ERROR_C0124("C0124", "消息分组未查到"),SERVICE_ERROR_C0130("C0130", "缓存服务出错"),SERVICE_ERROR_C0131("C0131", "key 长度超过限制"),SERVICE_ERROR_C0132("C0132", "value 长度超过限制"),SERVICE_ERROR_C0133("C0133", "存储容量已满"),SERVICE_ERROR_C0134("C0134", "不支持的数据格式"),SERVICE_ERROR_C0140("C0140", "配置服务出错"),SERVICE_ERROR_C0150("C0150", "网络资源服务出错"),SERVICE_ERROR_C0151("C0151", "VPN 服务出错"),SERVICE_ERROR_C0152("C0152", "CDN 服务出错"),SERVICE_ERROR_C0153("C0153", "域名解析服务出错"),SERVICE_ERROR_C0154("C0154", "网关服务出错"),/*** 二级宏观错误码*/SERVICE_ERROR_C0200("C0200", "第三方系统执行超时"),SERVICE_ERROR_C0210("C0210", "RPC 执行超时"),SERVICE_ERROR_C0220("C0220", "消息投递超时"),SERVICE_ERROR_C0230("C0230", "缓存服务超时"),SERVICE_ERROR_C0240("C0240", "配置服务超时"),SERVICE_ERROR_C0250("C0250", "数据库服务超时"),/*** 二级宏观错误码*/SERVICE_ERROR_C0300("C0300", "数据库服务出错"),SERVICE_ERROR_C0311("C0311", "表不存在"),SERVICE_ERROR_C0312("C0312", "列不存在"),SERVICE_ERROR_C0321("C0321", "多表关联中存在多个相同名称的列"),SERVICE_ERROR_C0331("C0331", "数据库死锁"),SERVICE_ERROR_C0341("C0341", "主键冲突"),/*** 二级宏观错误码*/SERVICE_ERROR_C0400("C0400", "第三方容灾系统被触发"),SERVICE_ERROR_C0401("C0401", "第三方系统限流"),SERVICE_ERROR_C0402("C0402", "第三方功能降级"),/*** 二级宏观错误码*/SERVICE_ERROR_C0500("C0500", "通知服务出错"),SERVICE_ERROR_C0501("C0501", "短信提醒服务失败"),SERVICE_ERROR_C0502("C0502", "语音提醒服务失败"),SERVICE_ERROR_C0503("C0503", "邮件提醒服务失败");private final String code;private final String description;private AliErrorCodeEnum(String code, String description) {this.code = code;this.description = description;}public String getCode() {return code;}public String getDescription() {return description;}
}

3.2 基于微服务的异常编码体系

第二种方法来源于gitee开源项目guns,大家可以直接找到项目阅读源码。感谢坐着提供的思路

3.2.1 构建基础异常和异常构造器

定义抽象异常编码枚举类

public interface AbstractExceptionEnum {/*** 获取异常的状态码*/String getErrorCode();/*** 获取给用户提示信息*/String getUserTip();}

定义基础构造器


@EqualsAndHashCode(callSuper = true)
public class ServiceException extends RuntimeException {/*** 错误码*/private String errorCode;/*** 返回给用户的提示信息*/private String userTip;/*** 异常的模块名称*/private String moduleName;/*** 根据模块名,错误码,用户提示直接抛出异常*/public ServiceException(String moduleName, String errorCode, String userTip) {super(userTip);this.errorCode = errorCode;this.moduleName = moduleName;this.userTip = userTip;}/*** 如果要直接抛出ServiceException,可以用这个构造函数*/public ServiceException(String moduleName, AbstractExceptionEnum exception) {super(exception.getUserTip());this.moduleName = moduleName;this.errorCode = exception.getErrorCode();this.userTip = exception.getUserTip();}/*** 不建议直接抛出ServiceException,因为这样无法确认是哪个模块抛出的异常* <p>* 建议使用业务异常时,都抛出自己模块的异常类*/public ServiceException(AbstractExceptionEnum exception) {super(exception.getUserTip());this.moduleName = RULE_MODULE_NAME;this.errorCode = exception.getErrorCode();this.userTip = exception.getUserTip();}}

3.2.2 如何在微服务中构建异常编码

以消息微服务举例

定义当前服务异常编码


public enum MessageExceptionEnum implements AbstractExceptionEnum {/*** 消息记录不存在*/NOT_EXISTED(Constants.BUSINESS_ERROR_TYPE_CODE + MessageConstants.MESSAGE_EXCEPTION_STEP_CODE + "01", "消息记录不存在,id为:{}");/*** 错误编码*/private final String errorCode;/*** 提示用户信息*/private final String userTip;MessageExceptionEnum(String errorCode, String userTip) {this.errorCode = errorCode;this.userTip = userTip;}}

异常抛出构造器

public class MessageException extends ServiceException {public MessageException(AbstractExceptionEnum exception, Object... params) {super(MessageConstants.MESSAGE_MODULE_NAME, exception.getErrorCode(), StrUtil.format(exception.getUserTip(), params));}public MessageException(AbstractExceptionEnum exception) {super(MessageConstants.MESSAGE_MODULE_NAME, exception);}}

抛出异常

if (userIds.isEmpty()) {throw new MessageException(MessageExceptionEnum.ERROR_RECEIVE_USER_IDS);}

3.2.4 异常开发规范

虽然有了框架,但是还需要遵守规范,防止时间久了被乱用

  1. new异常类必须是ServiceException的子类。
  2. 创建异常时,必须通过AbstractExceptionEnum枚举类或其子类构建。

简单来说就是所有的异常一定要在体系内,不允许直接指定异常编码(这种方式系统无记录),不推荐直接指定错误信息。

【精品必收藏】如何构建企业级微服务异常编码体系相关推荐

  1. 企业级微服务构建-01搭建和使用Maven私有仓库(Nexus)-09权限(Privileges)

    亲历的企业级微服务的完整构建过程-系列文章目录 本人参与了这次的企业级微服务的完整构建,想要记录下来以便以后复习,同时也想分享给小伙伴们,抛砖引玉,欢迎大家提出自己的意见和建议,大家一起探讨一起成长. ...

  2. 企业级微服务构建-01搭建和使用Maven私有仓库(Nexus)-29上传组件

    亲历的企业级微服务的完整构建过程-系列文章目录 本人参与了这次的企业级微服务的完整构建,想要记录下来以便以后复习,同时也想分享给小伙伴们,抛砖引玉,欢迎大家提出自己的意见和建议,大家一起探讨一起成长. ...

  3. 企业级微服务构建-01搭建和使用Maven私有仓库(Nexus)-03备份和恢复

    亲历的企业级微服务的完整构建过程-系列文章目录 本人参与了这次的企业级微服务的完整构建,想要记录下来以便以后复习,同时也想分享给小伙伴们,抛砖引玉,欢迎大家提出自己的意见和建议,大家一起探讨一起成长. ...

  4. 企业级微服务构建-01搭建和使用Maven私有仓库(Nexus)-05仓库管理

    亲历的企业级微服务的完整构建过程-系列文章目录 本人参与了这次的企业级微服务的完整构建,想要记录下来以便以后复习,同时也想分享给小伙伴们,抛砖引玉,欢迎大家提出自己的意见和建议,大家一起探讨一起成长. ...

  5. 企业级微服务构建-01搭建和使用Maven私有仓库(Nexus)-17审计

    亲历的企业级微服务的完整构建过程-系列文章目录 本人参与了这次的企业级微服务的完整构建,想要记录下来以便以后复习,同时也想分享给小伙伴们,抛砖引玉,欢迎大家提出自己的意见和建议,大家一起探讨一起成长. ...

  6. springcloud架构特点_打造企业级微服务平台架构,分布式应用场景管理

    微服务平台架构是一项在云中部署应用和服务的新技术.大部分围绕微服务的争论都集中在容器或其他技术是否能很好的实施微服务. 微服务系统可以在"自己的程序"中运行,并通过"轻量 ...

  7. 构建高性能微服务架构 【摘自刘超】

    随着移动互联网时代的兴起,提供高性能.高可用性.高扩展性的服务已经不仅仅是大公司的专利,而逐渐成为所有互联网+公司的标配需求.本文介绍网易如何利用多年的互联网架构经验和网易蜂巢的平台,帮助客户进行架构 ...

  8. 手把手0基础项目实战(一)——教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)......

    手把手0基础项目实战(一)--教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)... 原文: 手把手0基础项目实战(一)--教你搭建一套可自动化构 ...

  9. dubbo k8s 服务发现_工商银行基于 Dubbo 构建金融微服务架构的实践-服务发现篇

    作者 | 张远征来源|阿里巴巴云原生公众号 导读:Dubbo 作为分布式微服务框架,众多公司在实践中基于 Dubbo 进行分布式系统架构.重启开源后,我们不仅看到 Dubbo 3.0 最新的 Road ...

最新文章

  1. python将注释写入xml_python 注释xml的元素
  2. 使用Git上传项目到码云仓库
  3. Linux命令之Ethtool
  4. python面试经典问题_Python面试中最常见的25个问题-结束
  5. Kettle使用_13 表输入并发运行与复制数量
  6. CentOS 6 nginx(Tengine2.1.2)源码编译一键部署脚本
  7. 两个分数化简比怎么化_我学《分数的意义》心得
  8. 霸主–统治和管理API的地方
  9. from表单提交和JSON区别
  10. blender使用_用Blender教青少年3D动画
  11. [luogu P3128][USACO15DEC]Max Flow [LCA][树上差分]
  12. the server is not ready for publishing.Please check if the Publishing Tools on the server
  13. GraphQL 、flask-graphql、Graphene| 一种配得上凡尔赛的API框架
  14. PHP毕业设计源码带论文和答辩、大作业、实例程序源码下载合集【21套】
  15. 2021.12月电脑浏览器推荐-cent浏览器内存占用只有Google谷歌Chrome的68%
  16. qq第三方登录所需appid
  17. JavaScript点击图片加上红色边框
  18. 容斥定理与鸽巢定理(抽屉定理)
  19. 分布式--生成数据库全局唯一ID--方法/方案
  20. 苹果三代耳机_浅谈华强北最强Airpods Pro(苹果三代蓝牙耳机)到底怎么样?

热门文章

  1. 其他计算机如何联网,局域网怎么连接其他电脑上网
  2. 【单片机】STM32 最小板 学习笔记
  3. 扩展WiFi是什么意思
  4. 基于MATLAB编写的GNSS_SDR(GNSS软件接收机)——自学笔记(2)
  5. 一套基于模板匹配的语音识别技术。提取语音的特征,并建立模板库,可以将语音识别技术应用于机器人...
  6. VB.NET 之 Chr 函数
  7. Python中函数内如何调用另一个函数返回值
  8. Laravel Onion洋葱模型
  9. wordpress仅用代码轻松实现网站蜘蛛爬行记录
  10. 剑侠情缘修改服务器列表名字,史上奇葩的游戏氪金活动,充钱就能改服务器名,剑侠情缘也在其中...