一、前言
1、不规范的错误码有什么问题?
1)理解困难
描述:如果错误码的命名或描述不清晰,可能导致其他开发人员难以理解其含义。
举例:例如,一个错误码命名为“ERR1001”,没有进一步的注释或描述,可能导致其他开发人员不知道这个错误码代表的具体问题。
2)不一致性
描述: 如果错误码的命名、描述或分类不统一,可能导致代码的可读性和可维护性降低。
举例:例如,有的错误码使用三位数,有的使用两位数;有的错误码描述具体的问题,而有的描述则较为模糊。
3)排查困难
描述:如果错误码没有清晰的命名和描述,可能使得调试过程变得困难。
举例:当出现问题时,开发人员需要查看大量的日志或代码来定位问题所在。
4)冗余和重复
描述:如果错误码过多或过于复杂,可能导致代码中的错误处理逻辑变得冗余和重复。
举例:同一个错误可能在不同地方有不同的错误码,导致处理逻辑重复。
5)扩展性差
描述:如果错误码已经定义但后来需要添加新的错误码,可能需要修改多个地方的代码,增加了维护成本。
2、规范的错误码那么好,为什么不规范使用呢?
1)缺乏规范和标准:
在某些情况下,可能没有明确的规范或标准来指导如何使用错误码。这可能导致开发人员根据自己的理解和习惯来定义错误码,从而导致不规范的情况。
2)缺乏意识和经验:
某些开发人员可能没有意识到错误码规范化的重要性,或者缺乏足够的经验来正确地设计和使用错误码。
3)历史遗留问题:
在某些项目中,错误码可能已经使用了很长时间,而且已经成为了代码的一部分。在这种情况下,重新规范化错误码可能会涉及到大量的代码修改和测试,这可能会被视为成本较高。
4)个人习惯和偏好:
某些开发人员可能更倾向于按照自己的习惯和偏好来使用错误码,而不是遵循团队的规范。这可能会导致代码中的错误码使用不一致。
3、那怎么规范错误码呢
1)制定规范和标准:
团队可以制定明确的规范和标准,指导如何使用错误码,并将其纳入代码审查和开发流程中。
2)培训和指导:
为新开发人员提供培训和指导,使其了解如何正确地设计和使用错误码。
3)重构和改进:
对于历史遗留问题,可以通过逐步重构和改进的方式来规范化错误码的使用。
4)代码审查和团队协同:
通过代码审查和团队协同来确保错误码的规范化和一致性。
二、规范错误码
1、错误码-分片区
根据号段区分错误类型,这里长度定义了5位,可以根据自己系统规模调整长度
| 错误码 | 描述 |
|---|---|
| 00000 | 成功 |
| 10000 | 参数错误 |
| 20000 | 业务处理失败(业务上给用户吐出) |
| 30000 | RPC处理失败 --->>系统_失败分类(请求0、返回1)_业务_方法_调用方CODE码(代码补齐),极端情况下吐出 99999 |
| 40000 | 运行处理失败:一般内部处理使用,极端情况下吐出 99999 |
| 99999 | 系统太火爆了,请稍后重试! -->极端情况下才吐出 |
1@Getter 2@AllArgsConstructor 3enum ErrorCodeEnum implements CodeEnum { 4 5 ERROR_CODE_SUCCESS("00000", "成功"), 6 ERROR_CODE_PARAMS_ERROR("10000", "参数错误"), 7 ERROR_CODE_BUSINESS_ERROR("20000", "业务处理失败"), 8 ERROR_CODE_PRC_ERROR("30000", "RPC处理失败"), 9 ERROR_CODE_RUNTIME_ERROR("40000", "运行时失败"), 10 ERROR_CODE_FAIL("99999", "系统太火爆了,请稍后重试!"), 11 ; 12 private final String code; 13 private final String msg; 14 15} 16 17
2、10000-参数异常
非常简单,直接吐出即可
| 参数 | 说明 |
|---|---|
code | 错误码 |
msg | 返回错误信息 |
1 @Getter 2 @AllArgsConstructor 3 enum ParamsErrorEnum implements CodeEnum { 4 5 ERROR_CODE_10000("10000", "参数错误"), 6 ERROR_CODE_10001("10001", "不支持的请求方式"), 7 ERROR_CODE_10002("10002", "参数格式异常"), 8 9 ; 10 private final String code; 11 12 private final String msg; 13 14 15 } 16
3、20000-业务异常
| 参数 | 说明 |
|---|---|
code | 错误码 |
msg | 底层-错误信息 |
showMsg | 吐出-错误信息 |
1@Getter 2@AllArgsConstructor 3enum BusinessErrorEnum implements CodeEnum { 4 5 ERROR_CODE_20000("20000", "业务处理失败", "系统太火爆了,请稍后重试!"), 6 ERROR_CODE_20001("20001", "订单创建失败", "您有一个订单正在创建,请稍后查看"), 7 ERROR_CODE_20002("20002", "付款失败,存在创建中的订单", "您的订单付款失败,请稍后查看"), 8 ERROR_CODE_20003("20003", "付款失败,存在未支付的订单", "您的订单付款失败,请稍后查看"), 9 10 ; 11 private final String code; 12 13 private final String msg; 14 15 private final String showMsg; 16} 17
4、30000-RPC异常
该异常一定要合理使用,这样会让微服务直接错误信息更明确
说明:
系统_失败分类(请求0、返回1)_业务_调用方法_调用方CODE码(代码补齐)
| 字段 | 说明 |
|---|---|
| 系统 | 调用系统:如用户系统User |
| 失败分类 | 请求失败:0;返回失败:1 |
| 业务 | 业务(3开头):用户信息业务:30001 |
| 调用方法 | 业务调用方法(指定一个数字,确保是该业务唯一的方法) |
调用方Code码 | 后续代码中补齐,具体看异常抛出错误码使用 |
| 参数 | 说明 |
|---|---|
code | 错误码:系统_失败分类(请求0、返回1)_业务_方法_调用方CODE码(代码补齐) |
msg | 底层-错误信息 |
1@Getter 2@AllArgsConstructor 3enum RpcErrorEnum implements CodeEnum { 4 5 /** 6 * 系统_失败分类(请求0、返回1)_业务_方法_调用方CODE码(代码补齐) 7 */ 8 ERROR_CODE_USER_0_30001_0001("USER_0_30001_0001", "RPC异常-USER-用户信息-查询单个用户信息-接口调用失败"), 9 ERROR_CODE_USER_1_30001_0001("USER_1_30001_0001", "RPC异常-USER-用户信息-查询单个用户信息-接口返回失败"), 10 ERROR_CODE_USER_1_30001_0002("USER_1_30001_0002", "RPC异常-USER-用户信息-分页查询用户信息-接口返回失败"), 11 ; 12 private final String code; 13 private final String msg; 14} 15
5、40000-运行异常
1@Getter 2@AllArgsConstructor 3enum PlatformErrorEnum implements CodeEnum { 4 5 ERROR_CODE_40000("40000", "运行时失败"), 6 ERROR_CODE_40001("40001", "路由消息处理失败"), 7 8 ; 9 private final String code; 10 11 private final String msg; 12 13} 14 15
三、错误码使用
1、10000-参数异常
| 构造器 | 说明 |
|---|---|
ParameterException(CodeEnum.ParamsErrorEnum paramErrorEnum) | 建议使用:传入一个固定的枚举值 |
ParameterException(String message) | 不推荐:传入一个错误信息 |
1@Getter 2public class ParameterException extends RuntimeException { 3 4 5 /** 6 * serialVersionUID 7 */ 8 private static final long serialVersionUID = -6114625076221233075L; 9 /** 10 * 返回错误码 11 */ 12 private final String code; 13 14 15 /** 16 * BusinessException 17 * 18 * @param paramErrorEnum paramErrorEnum 19 */ 20 public ParameterException(CodeEnum.ParamsErrorEnum paramErrorEnum) { 21 super(paramErrorEnum.getMsg()); 22 this.code = paramErrorEnum.getCode(); 23 } 24 25 /** 26 * ParameterErrorException 27 * 28 * @param message message 29 */ 30 public ParameterException(String message) { 31 super(message); 32 this.code = CodeEnum.ErrorCodeEnum.ERROR_CODE_PARAMS_ERROR.getCode(); 33 } 34 35} 36
2、20000-业务异常
| 构造器 | 说明 |
|---|---|
BusinessException(CodeEnum.BusinessErrorEnum businessErrorEnum) | 建议使用:传入一个固定的枚举值 |
BusinessException(String message) | 不推荐:传入一个错误信息 |
1@Getter 2public class BusinessException extends RuntimeException { 3 4 /** 5 * serialVersionUID 6 */ 7 private static final long serialVersionUID = 799633539625676004L; 8 9 /** 10 * 返回错误码 11 */ 12 private final String code; 13 14 /** 15 * 展示信息 16 */ 17 private final String showMsg; 18 19 20 /** 21 * BusinessException 22 * 23 * @param businessErrorEnum businessErrorEnum 24 */ 25 public BusinessException(CodeEnum.BusinessErrorEnum businessErrorEnum) { 26 super(businessErrorEnum.getMsg()); 27 this.code = businessErrorEnum.getCode(); 28 this.showMsg = businessErrorEnum.getShowMsg(); 29 30 } 31 32 /** 33 * BusinessException 34 * 35 * @param message message 36 */ 37 public BusinessException(String message) { 38 super(message); 39 this.code = CodeEnum.ErrorCodeEnum.ERROR_CODE_BUSINESS_ERROR.getCode(); 40 this.showMsg = message; 41 } 42 43} 44
3、30000-RPC异常
| 构造器 | 说明 |
|---|---|
RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum) | 场景:处理未知的RPC异常,如网络超时等 |
RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum, String code, String showMsg) | 场景:处理已知的异常 |
RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum, String code, String msg, String showMsg) | 场景:处理已知的异常 |
1@Getter 2public class RpcException extends RuntimeException { 3 4 /** 5 * serialVersionUID 6 */ 7 private static final long serialVersionUID = 799633539625676004L; 8 9 /** 10 * 返回错误码 11 */ 12 private final String code; 13 14 /** 15 * 展示信息 16 */ 17 private final String showMsg; 18 19 /** 20 * RpcException-处理未知的异常 21 * 22 * 23 * @param rpcErrorEnum rpcErrorEnum 24 */ 25 public RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum) { 26 super(rpcErrorEnum.getMsg()); 27 this.code = rpcErrorEnum.getCode(); 28 this.showMsg = CodeEnum.ErrorCodeEnum.ERROR_CODE_FAIL.getMsg(); 29 } 30 31 /** 32 * RpcException 处理已知的异常 33 * 34 * @param rpcErrorEnum rpcErrorEnum 35 * @param code code 36 * @param showMsg showMsg 37 */ 38 public RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum, String code, String showMsg) { 39 super(rpcErrorEnum.getMsg()); 40 this.code = rpcErrorEnum.getCode() + "_" + code; 41 this.showMsg = showMsg; 42 } 43 44 /** 45 * RpcException 处理已知的异常 46 * 47 * @param rpcErrorEnum rpcErrorEnum 48 * @param code code 49 * @param showMsg showMsg 50 */ 51 public RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum, String code, String msg, String showMsg) { 52 super(msg); 53 this.code = rpcErrorEnum.getCode() + "_" + code; 54 this.showMsg = showMsg; 55 } 56 57} 58
4、40000-运行异常
1@Getter 2public class PlatformException extends RuntimeException { 3 4 private static final long serialVersionUID = 5535821215702463243L; 5 /** 6 * 返回错误码 7 */ 8 private final String code; 9 10 /** 11 * 展示信息 12 */ 13 private final String showMsg; 14 15 /** 16 * PlatformException 17 * 18 * @param platformErrorEnum platformErrorEnum 19 */ 20 public PlatformException(CodeEnum.PlatformErrorEnum platformErrorEnum) { 21 super(platformErrorEnum.getMsg()); 22 this.code = platformErrorEnum.getCode(); 23 this.showMsg = CodeEnum.ErrorCodeEnum.ERROR_CODE_FAIL.getMsg(); 24 25 } 26} 27
四、异常吐出
1、10000-参数异常
1 2/** 3 * 不支持的请求方始 4 */ 5@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class) 6@ResponseStatus(value = HttpStatus.METHOD_NOT_ALLOWED) 7public BaseRes<?> methodNotSupportExceptionHandler(HttpRequestMethodNotSupportedException e) { 8 log.error("不支持的请求方式", e); 9 return BaseRes.buildFailure(CodeEnum.ParamsErrorEnum.ERROR_CODE_10001.getCode(), e.getMessage()); 10} 11 12/** 13 * 参数类型错误 14 */ 15@ExceptionHandler(value = {BindException.class}) 16@ResponseStatus(HttpStatus.BAD_REQUEST) 17@ResponseBody 18public BaseRes<?> bindExceptionHandler(BindException e) { 19 log.error("====参数类型错误===", e); 20 return BaseRes.buildFailure(CodeEnum.ParamsErrorEnum.ERROR_CODE_10000); 21} 22 23/** 24 * 参数格式问题 25 */ 26@ExceptionHandler(value = {MethodArgumentTypeMismatchException.class, 27 HttpMessageConversionException.class, UnexpectedTypeException.class}) 28@ResponseStatus(HttpStatus.BAD_REQUEST) 29@ResponseBody 30public BaseRes<?> httpMessageConversionExceptionHandler(Exception e) { 31 log.error("====参数格式异常===", e); 32 return BaseRes.buildFailure(CodeEnum.ParamsErrorEnum.ERROR_CODE_10002); 33} 34 35/** 36 * 参数错误 37 */ 38@ExceptionHandler(value = ParameterException.class) 39@ResponseStatus(HttpStatus.BAD_REQUEST) 40@ResponseBody 41public BaseRes<?> parameterErrorExceptionHandler(ParameterException e) { 42 log.error("====参数异常:code:{},msg:{}", e.getCode(), e.getMessage(), e); 43 return BaseRes.buildFailure(e.getCode(), e.getMessage()); 44} 45 46
2、20000-业务异常
1/** 2 * 业务异常,给前台返回异常数据 3 */ 4@ExceptionHandler(value = BusinessException.class) 5@ResponseStatus(HttpStatus.BAD_REQUEST) 6@ResponseBody 7public BaseRes<?> businessExceptionHandler(BusinessException e) { 8 log.error("====业务异常:code:{},msg:{},showMsg:{}", e.getCode(), e.getMessage(), e.getShowMsg(), e); 9 return BaseRes.buildFailure(e.getCode(), e.getShowMsg()); 10} 11 12
3、30000-RPC异常
1/** 2 * RPC,给前台返回异常数据 3 */ 4@ExceptionHandler(value = RpcException.class) 5@ResponseStatus(HttpStatus.BAD_REQUEST) 6@ResponseBody 7public BaseRes<?> rpcExceptionHandler(RpcException e) { 8 log.error("====RPC异常:code:{},msg:{},showMsg:{}", e.getCode(), e.getMessage(), e.getShowMsg(), e); 9 return BaseRes.buildFailure(e.getCode(), e.getShowMsg()); 10} 11
4、40000-运行异常
1 2/** 3 * 运行异常,给前台返回异常数据 4 */ 5@ExceptionHandler(value = PlatformException.class) 6@ResponseStatus(HttpStatus.BAD_REQUEST) 7@ResponseBody 8public BaseRes<?> rpcExceptionHandler(PlatformException e) { 9 log.error("====运行异常:code:{},msg:{},showMsg:{}", e.getCode(), e.getMessage(), e.getShowMsg(), e); 10 return BaseRes.buildFailure(e.getCode(), e.getShowMsg()); 11} 12
五、Demo
1、10000-参数异常
1@ApiOperation("parameterExceptionEnum") 2@LogIndex 3@GetMapping("parameterExceptionEnum") 4@ResponseBody 5public BaseRes<List<UserDemoVO>> parameterExceptionEnum() { 6 throw new ParameterException(CodeEnum.ParamsErrorEnum.ERROR_CODE_10002); 7} 8 9{ 10 "success": false, 11 "data": null, 12 "msg": "参数格式异常", 13 "code": "10002" 14} 15
1@ApiOperation("parameterExceptionMsg") 2@LogIndex 3@GetMapping("parameterExceptionMsg") 4@ResponseBody 5public BaseRes<List<UserDemoVO>> parameterExceptionMsg() { 6 throw new ParameterException("用户Id不能为空"); 7} 8 9 10{ 11 "success": false, 12 "data": null, 13 "msg": "用户Id不能为空", 14 "code": "10000" 15} 16
2、20000-业务异常
1@ApiOperation("businessExceptionEnum") 2@LogIndex 3@GetMapping("businessExceptionEnum") 4@ResponseBody 5public BaseRes<List<UserDemoVO>> businessExceptionEnum() { 6 throw new BusinessException(CodeEnum.BusinessErrorEnum.ERROR_CODE_20001); 7} 8 9 10{ 11 "success": false, 12 "data": null, 13 "msg": "您有一个订单正在创建,请稍后查看", 14 "code": "20001" 15} 16
1@ApiOperation("businessExceptionMsg") 2@LogIndex 3@GetMapping("businessExceptionMsg") 4@ResponseBody 5public BaseRes<List<UserDemoVO>> businessExceptionMsg() { 6 throw new BusinessException("用户创建失败"); 7} 8 9{ 10 "success": false, 11 "data": null, 12 "msg": "用户创建失败", 13 "code": "20000" 14} 15
3、30000-RPC异常
1 @ApiOperation("rpcExceptionDefaultEnum") 2 @LogIndex 3 @GetMapping("rpcExceptionDefaultEnum") 4 @ResponseBody 5 public BaseRes<List<UserDemoVO>> rpcExceptionDefaultEnum() { 6 throw new RpcException(CodeEnum.RpcErrorEnum.ERROR_CODE_USER_0_30001_0001); 7 } 8 9{ 10 "success": false, 11 "data": null, 12 "msg": "系统太火爆了,请稍后重试!", 13 "code": "USER_0_30001_0001" 14} 15
1@ApiOperation("rpcExceptionEnumShowMsg") 2@LogIndex 3@GetMapping("rpcExceptionEnumShowMsg") 4@ResponseBody 5public BaseRes<List<UserDemoVO>> rpcExceptionEnumShowMsg() { 6 throw new RpcException(CodeEnum.RpcErrorEnum.ERROR_CODE_USER_1_30001_0001, "1000", "用户不存在"); 7} 8 9{ 10 "success": false, 11 "data": null, 12 "msg": "用户不存在", 13 "code": "USER_1_30001_0001_1000" 14} 15
1@ApiOperation("rpcExceptionEnumMsg") 2@LogIndex 3@GetMapping("rpcExceptionEnumMsg") 4@ResponseBody 5public BaseRes<List<UserDemoVO>> rpcExceptionEnumMsg() { 6 throw new RpcException(CodeEnum.RpcErrorEnum.ERROR_CODE_USER_1_30001_0001, 7 "1000", "底层结构异常", "用户不存在"); 8} 9 10 11 12{ 13 "success": false, 14 "data": null, 15 "msg": "用户不存在", 16 "code": "USER_1_30001_0001_1000" 17} 18
4、40000-运行异常
1@ApiOperation("platformException") 2@LogIndex 3@GetMapping("platformException") 4@ResponseBody 5public BaseRes<List<UserDemoVO>> platformException() { 6 throw new PlatformException(CodeEnum.PlatformErrorEnum.ERROR_CODE_40001); 7} 8 9 10 11{ 12 "success": false, 13 "data": null, 14 "msg": "系统太火爆了,请稍后重试!", 15 "code": "40001" 16} 17
作者:京东保险 张宇晋
来源:京东云开发者社区 转载请注明来源
