后端

您所在的位置:网站首页 错误码0030 后端

后端

#后端| 来源: 网络整理| 查看: 265

趁热记录下,给未来的自己

0. 前言

在一个项目乃乃至整个团队在所有项目的开发过程中,统一设计和规范使用错误码,是必须要落实的一个点。

错误码的设计,直接关系到后端接口的条理性和优雅性;错误码的使用,直接关系到开发人员的开发规范和开发效率。

所以,对错误码进行优雅的管理,是非常有必要的,是一个团队的基石之一。

下面,我会从如何设计,管理和多语言错误码的具体实现等三个方面一一阐述。

1. 设计

首先,需要对错误码大致分为两类:

通用错误码 特殊含义错误码

其次,错误码需要包含的要素:

错误码 中文错误信息 英文错误信息 1.1 通用错误码

主要包含:成功和失败(未知错误)

SUCCESS( "10000", "成功", "ok" ), UNKNOWN_ERROR( "-1", "未知错误", "unknown error" ) 1.2 特殊含义错误码

和用户相关的错误, 如: A_PARAM_VALIDATION_ERROR( "A0100", "参数校验失败", "parameter validation error" )

和第三方依赖相关的错误, 如: B_STORAGE_ERROR("B0100", "持久化存储错误", "storage error")

和当前业务系统相关的错误, 如: C_RESOURCE_OUT_ERROR( "C0100", "系统资源异常", "system resource error" )

2. 管理

由于目前没有人力投入到错误码管理平台的开发,市面上也没有比较合适的开源项目可以使用,因此,暂时使用飞书文档做错误码管理。略。

3. 具体实现

代码侧,首先要有一个枚举类,用于存放所有错误码。

错误码枚举类 public enum ReturnEnum { /** * 成功 */ SUCCESS( "10000", "成功", "ok" ) , /** * 未知错误 */ UNKNOWN_ERROR( "-1", "未知错误", "unknown error" ) , /** * 一级宏观错误码,和用户相关 */ A_USER_CLIENT_ERROR( "A0000", "用户端错误", "user client error" ) , /** * 一级宏观错误码,和第三方服务相关:数据库,缓存,第三方接口等 */ B_GENERAL_3RD_ERROR( "B0000", "一般三方依赖错误", "general 3rd error" ) , /** * 二级宏观错误码,持久化存储错误,主要和 mysql 相关 */ B_STORAGE_ERROR( "B0100", "持久化存储错误", "storage error" ) , B_SQL_INTEGRITY_CONSTRAINT_VIOLATION_ERROR( "B0101", "违反数据库索引约束错误", "sql integrity constraint violation" ) , B_DUPLICATE_KEY_ERROR( "B0102", "违反数据库唯一索引约束错误", "duplicated key" ) , B_QUERY_NO_RESULT( "B0103", "没有查询到数据", "no data queried" ) , B_MINIO_UPLOAD_URL_ERROR( "B0104", "获取文件上传链接错误", "get upload file url error" ) , /** * 二级宏观错误码,缓存存储错误,主要和 redis 相关 */ B_CACHE_ERROR( "B0200", "缓存错误", "cache error" ) , B_CACHE_REDIS_SET_ERROR( "B0201", "缓存写入异常", "cache set error" ) , B_CACHE_REDIS_DEL_ERROR( "B0202", "缓存删除异常", "cache del error" ) , B_CACHE_REDIS_GET_ERROR( "B0203", "缓存获取异常", "cache get error" ) , /** * 二级宏观错误码,和第三方接口有关 */ B_3RD_API_ERROR( "B0300", "第三方接口异常", "3rd api error" ) , /** * 一级宏观错误码,和当前系统相关:业务逻辑,程序健壮性等 */ C_GENERAL_BUSINESS_ERROR( "B0000", "一般业务错误", "general business error" ) , /** ; String msgCode; String msgCn; String msgEn; } 增加一个拦截器LanguageInterceptor public class LanguageInterceptor implements HandlerInterceptor { @Override public boolean preHandle ( HttpServletRequest request, HttpServletResponse response, Object handler ) throws Exception { String acceptLanguage = request.getHeader ( HttpHeaders.ACCEPT_LANGUAGE) ; RequestHolderUtil.addLang( acceptLanguage ) ; return true; } @Override public void postHandle ( HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView ) throws Exception { } @Override public void afterCompletion ( HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex ) throws Exception { RequestHolderUtil.remove() ; } } public class RequestHolderUtil { private static final ThreadLocal requestHolder = new ThreadLocal(); public RequestHolderUtil() { } public static void addLang(String language) { requestHolder.set(language); } public static String getLang() { return (String)requestHolder.get(); } public static void remove() { requestHolder.remove(); } } 注册拦截器 @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors ( InterceptorRegistry registry ) { registry.addInterceptor ( new LanguageInterceptor ()) .addPathPatterns ( "/**" ) ; } } 返回包装类 @Data @AllArgsConstructor @Slf4j public class ReturnBase implements Serializable { private static final long serialVersionUID = 1L; /** * 日志跟踪标识 */ public static final String TRACE_ID = "TRACE_ID"; private String traceId; private String msgCode; private String msg; private Object data; private Integer total; ... public static ReturnBase error ( ReturnEnum returnEnum ) { return error( returnEnum, RequestHolderUtil.getLang()) ; } public static ReturnBase error(ReturnEnum returnEnum, String language) { String msg; if (Objects.isNull(language)) { return new ReturnBase(MDC.get(TRACE_ID), returnEnum.getMsgCode(), returnEnum.getMsgEn(), null, 0); } switch(language){ case CommonConstant.SIMPLE_CHINESE: msg = returnEnum.getMsgCn(); break; default: msg = returnEnum.getMsgEn(); break; } return new ReturnBase(MDC.get(TRACE_ID), returnEnum.getMsgCode(), msg, null, 0); } ... public static String MsgFormat ( String code, String msg ) { return String.format( "%s (error: %s)", msg, code ) ; } } 使用示例

前端发起请求,在header里携带HttpHeaders.``ACCEPT_LANGUAGE``=zh-Hans ;

后端LanguageInterceptor拦截器拦截后,将ACCEPT_LANGUAGE 塞入当前请求的Threadlocal*变量里;

后端返回错误码给前端:ReturnBase.error(``ReturnEnum``.``C_GENERAL_BUSINESS_ERROR``); 在ReturnBase.error()方法中,会根据之前塞入到Threadlocal里的ACCEPT_LANGUAGE变量,自动选择返回中文还是英文的错误文案。



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3