Springboot配置全局异常通用返回

admin 2025年5月23日15:49:41评论7 views字数 4488阅读14分57秒阅读模式

点击上方“IT那活儿”公众号--专注于企业全栈运维技术分享,不管IT什么活儿,干就完了!!!

背 景

后端接口出参的格式总是千奇百怪,没有一个固定的格式,错误信息提示也不明朗,业务的状态码总是东一个西一个,前端这都不好做统一的管理操作, 开始研究起对出参的统一封转。

简单的业务状态+详情出参

code 约定为业务结果码 2000成功,5000失败,message 约定为错误提示信息,data 约定为返回的出参内容。

对此就形成了固定的出参json格式如下:

json{"code":2000,"message":"成功","data":{}}

前端可以根据不同的code返回,做不同逻辑处理:

  • code = 2000,做成功data数据内容的展示;
  • code = 5000,做失败的提示语message提示。

通过Http状态码判断:

针对特殊场景的判定,可以根据Http状态码来判断,因为每个请求都有对应的http请求的状态码返回,例如200,500,401,404等常用的状态码,也能当作前端判断请求的情况的依据。

  • 2xx(成功状态码)
    200 (OK):请求成功;
    201 (Created):请求成功,服务器对应资源已创建;
    202 (Accepted):服务器接受请求,但还没处理好;
    204 (No Content): 服务器成功处理请求,但没有内容返回;
    205 (Reset Content): 服务器成功处理请求,要求客户端重置之前显示内容;
    206 (Partial Content): 服务器成功处理部分请求,用于断点续传。
  • 3xx(重定向状态码)
    301 (Moved Permanently): 请求资源已经换成新的url,望客户端请求新的地址Location的url;
    302 (Found): 请求资源暂时换成新的url;
    304 (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则提供具体的错误细节,两者结合可以让前端更全面地了解错误情况。

封装常量的案例

4.1 请求状态码的枚举值

代码解读:

@Getterpublicenum ResultEnum {    SUCCESS("请求成功"2000),    ERROR("服务器内部错误"5000),    PARAM_ERROR("参数错误"4001),    ;privateString msg;private Integer code;    ResultEnum(String msg, Integer code) {this.msg = msg;this.code = code;    }}

4.2 统一出参的格式封装

代码解读:

@DatapublicclassResultData<T{/**     * 默认生成的序列号     */privatestaticfinallong serialVersionUID = 1L;private Integer code = 2000;//默认成功private String msg = "";private T data;publicResultData(Integer code, String msg){this.code = code;this.msg = msg;    }publicResultData(Integer code, String msg, T data){this.code = code;this.msg = msg;this.data = data;    }publicstatic <T> ResultData<T> error(Integer code, String msg){returnnew ResultData<T>(code, msg);    }publicstatic <T> ResultData<T> error(String msg){returnnew ResultData<T>(ResultEnum.ERROR.getCode(), msg);    }publicstatic <T> ResultData<T> success(String msg){returnnew ResultData<T>(ResultEnum.SUCCESS.getCode(), msg);    }publicstatic <T> ResultData<T> success(String msg, T data){returnnew ResultData<T>(ResultEnum.SUCCESS.getCode(), msg, data);    }}

4.3 全局异常处理

@RestControllerAdvice是 Spring 框架提供的用于全局异常处理的注解 ,通过该注解可以是实现集中在一个类中处理异常的问题,避免重复处理异常代码 , 在具体的方法上使用@ExceptionHandler针对性的处理不同异常导致的问题。

代码解读:

@RestControllerAdvicepublicclassGlobalExceptionHandlerAdvice{@ExceptionHandler(MethodArgumentNotValidException.class)public ResultData<Object> 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 处理异常优先级:

处理的优先级,必然是有精确匹配到的异常处理方法先走,如果没有精确匹配的异常处理,会根据子类->父类的顺序来处理 。

如有如下三种异常:

  • ExceptionA,

  • ExceptionB,

  • ExceptionC 

ExceptionA 是 ExceptionB的父类,ExceptionB是ExceptionC的父类。

代码解读:

@ExceptionHandler(ExceptionA.class)@ResponseBodypublic ResultData<Object> ExceptionASolve(ExceptionA e) {}@ExceptionHandler(ExceptionB.class)@ResponseBodypublic ResultData<Object> exceptionBSolve(ExceptionB e) {}

代码解读:

@RequestMapping("/hello")publicString hello() {thrownew ExceptionC("sss");}

此时对应请求抛出ExceptionC,全局处理异常方法exceptionBSolve会去对应处理它。

注意: 当然还有另外一种情况,你在方法体里定义对同一个异常处理下有多个方法,会导致最后执行到哪个方法是属于不确定性的,因为会取决于方法的定义顺序,类的加载顺序等因素。

总 结:

和前端沟通设计好统一的返回模板,便于前端进行交互,一般场景下,可以直接使用简单的通用模板来返回。针对额外复杂的场景可以适当的增加参数做区分判断。还有就是对异常进行统一的集中处理,封装成模板返回给前端。

Springboot配置全局异常通用返回
END

本文作者:廖鸿桓(上海新炬中北团队)

本文来源:“IT那活儿”公众号

Springboot配置全局异常通用返回

原文始发于微信公众号(网络安全与取证研究):Springboot配置全局异常通用返回

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月23日15:49:41
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Springboot配置全局异常通用返回https://cn-sec.com/archives/4084807.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息