网站欢迎页面在线设计,重庆网站的网络推广,wordpress 转发 插件,华为公司网站建设受众是Springboot配置全局异常通用返回
前言
前端对接了部分接口后#xff0c;开始抱怨#xff0c;“后端接口出参的格式总是千奇百怪#xff0c;没有一个固定的格式#xff0c;错误信息提示也不明朗#xff0c;业务的状态码总是东一个西一个#xff0c;前端这都不好做统一的…Springboot配置全局异常通用返回
前言
前端对接了部分接口后开始抱怨“后端接口出参的格式总是千奇百怪没有一个固定的格式错误信息提示也不明朗业务的状态码总是东一个西一个前端这都不好做统一的管理操作”对此后端开始研究起对出参的统一封转。
约定统一的格式
通过对所有的出参都有固定的格式输出可以让前端封装拦截器来对请求不同逻辑走向的处理。
简单的业务状态详情出参
code 约定为业务结果码 2000成功5000失败message 约定为错误提示信息data 约定为返回的出参内容。对此就形成了固定的出参json格式如下
{code:2000,message:成功,data:{}
}前端可以根据不同的code返回做不同逻辑处理
code 2000 做成功data数据内容的展示code 5000 做失败的提示语message提示
通过Http状态码判断
针对特殊场景的判定可以根据Http状态码来判断因为每个请求都有对应的http请求的状态码返回例如200500401404等常用的状态码也能当作前端判断请求的情况的依据。
2xx(成功状态码) 200 (OK)请求成功201 (Created)请求成功服务器对应资源已创建202 (Accepted)服务器接受请求但还没处理好204 (No Content): 服务器成功处理请求但没有内容返回205 (Reset Content): 服务器成功处理请求,要求客户端重置之前显示内容206 (Partial Content): 服务器成功处理部分请求用于断点续传 3xx(重定向状态码) 301 (Moved Permanently): 请求资源已经换成新的url望客户端请求新的地址Location的url302 (Found): 请求资源暂时换成新的url304 (Not Modified) : 服务端判断是否资源没被修改浏览器使用本地缓存 4xx(客户端错误状态码) 400 (Bad Request) 客户端请求格式有问题401 (Unauthorized) : 未认证或者认证失败403 (Forbidden) : 没有对应的权限404 (Not Found): 服务器找不到对应的客户端请求的资源405 (Method Not Allowed) : 客户端请求方法不被服务端允许要求的 5xx(服务端错误状态码) 500 (Internal Server Error) : 服务器内部程序代码等引起的错误502 (Bad Gateway)作为网关收到服务器无效的响应503 (Service Unavailable) : 服务器无法提供服务504 (Gateway Time - out) : 作为网关收到服务器响应超时过慢
复杂展示的业务场景
对于单一code无法描述的场景可以再额外增添参数来描述具体的场景情况。
errorDetails: 错误对象具体字段描述在指定code为4000-4999之前的错误是有 field 指定具体错误字段errorMsg 指定具体错误信息 timestamp(可选) : 记录请求时间version(可选) 记录接口版本traceId(可选)记录链路追踪id
{code:4000,message:提交格式错误data:null,errorDetails:[{field:username,errorMsg:名称必须在6-20个字符内}]
}message字段提供一个整体的错误概述errorDetails则提供具体的错误细节两者结合可以让前端更全面地了解错误情况
封装常量的案例
请求状态码的枚举值
Getter
public enum ResultEnum {SUCCESS(请求成功, 2000),ERROR(服务器内部错误, 5000),PARAM_ERROR(参数错误, 4001),;private String msg;private Integer code;ResultEnum(String msg, Integer code) {this.msg msg;this.code code;}
}统一出参的格式封装
Data
public class ResultDataT {/*** 默认生成的序列号*/private static final long serialVersionUID 1L;private Integer code 2000;//默认成功private String msg ;private T data;public ResultData(Integer code, String msg) {this.code code;this.msg msg;}public ResultData(Integer code, String msg, T data) {this.code code;this.msg msg;this.data data;}public static T ResultDataT error(Integer code, String msg) {return new ResultDataT(code, msg);}public static T ResultDataT error(String msg) {return new ResultDataT(ResultEnum.ERROR.getCode(), msg);}public static T ResultDataT success(String msg) {return new ResultDataT(ResultEnum.SUCCESS.getCode(), msg);}public static T ResultDataT success(String msg, T data) {return new ResultDataT(ResultEnum.SUCCESS.getCode(), msg, data);}}全局异常处理
RestControllerAdvice是 Spring 框架提供的用于全局异常处理的注解 通过该注解可以是实现集中在一个类中处理异常的问题避免重复处理异常代码 , 在具体的方法上使用ExceptionHandler针对性的处理不同异常导致的问题
使用方式
RestControllerAdvice
public class GlobalExceptionHandlerAdvice {ExceptionHandler(MethodArgumentNotValidException.class)public ResultDataObject resolveMethodArgumentNotValidException(MethodArgumentNotValidException e) {FieldError fieldError e.getBindingResult().getFieldError();log.error(【参数校验异常】错误提示:{}, fieldError ! null ? fieldError.getDefaultMessage() : );return ResultData.error(ResultEnum.PARAM_ERROR.getCode(), e.getBindingResult().getFieldError().getDefaultMessage());}
}例如对于之前使用参数校验时Valid或Validated进行参数验证失败的情况抛出的MethodArgumentNotValidException异常就会统一到上述这个方法上处理bindingResult中能获取到错误的字段和错误的信息将其打印出来和结果值返回给前端
常见的需补充的错误异常
还有一些其他异常可以选择性的对其进行一一的处理封装成ResultData返回给前端最后兜底使用Exception处理异常保证最后输出还是为统一格式。
SQLException、DataAccessException : 与数据库交互过程中产生的异常HttpRequestMethodNotSupportedException 请求方式不支持的异常MethodArgumentNotValidException、 ConstraintViolationException 使用Valid或Validated时校验参数时可能会遇到的异常HttpMessageNotReadableException、HttpMessageNotWritableException 请求体的数据读写导致的问题IllegalArgumentException : 参数格式错误的异常CustomeException(自定义异常)自定义实现标识特定异常错误Exception 最后兜底顶级的异常保证异常处理最后会走到的地方
ExceptionHandler 处理异常优先级
处理的优先级必然是有精确匹配到的异常处理方法先走如果没有精确匹配的异常处理会根据子类-父类的顺序来处理 。
如有如下三种异常ExceptionAExceptionBExceptionC 分别是ExceptionA 是 ExceptionB的父类ExceptionB是ExceptionC的父类
ExceptionHandler(ExceptionA.class)
ResponseBody
public ResultDataObject ExceptionASolve(ExceptionA e) {
}ExceptionHandler(ExceptionB.class)
ResponseBody
public ResultDataObject exceptionBSolve(ExceptionB e) {
}
RequestMapping(/hello)
public String hello() {throw new ExceptionC(sss);
}此时对应请求抛出ExceptionC全局处理异常方法exceptionBSolve会去对应处理它
注意 当然还有另外一种情况你在方法体里定义对同一个异常处理下有多个方法会导致最后执行到哪个方法是属于不确定性的因为会取决于方法的定义顺序类的加载顺序等因素。
总结
和前端沟通设计好统一的返回模板便于前端进行交互一般场景下可以直接使用简单的通用模板来返回。针对额外复杂的场景可以适当的增加参数做区分判断。还有就是对异常进行统一的集中处理封装成模板返回给前端。