我们目前已经设计出了,包含全局响应,异常错误响应进行了统一返回。但是错误内容我们设计的比较模糊统一,还可以进行细化这样更有利于定位错误
当我们需要调用Http接口时,无论是在Web端还是移动端,都有可能遇到各种错误,例如参数缺失、类型错误、系统错误等。为了规范错误信息的返回,我们需要定义一个统一的接口错误返回值。通过对接口错误返回值的统一设计,我们可以规范调用方对各种不同错误的处理方式,并提供更加详细、准确的错误提示,同时也帮助后端实现接口返回值的规范化设计。因此,接口错误返回值的设计不仅仅是对错误信息的规范化处理,还涉及到业务上的错误设计。这样的设计可以有效地提高接口的使用效率和可维护性。
错误码定义
根据 http stats
错误通常可以分为以下几大类
- 200:请求成功
- 400:请求参数错误
- 401:未授权访问
- 403:表示禁止访问资源。
- 404:表示未找到资源。
- 500:表示服务器内部错误。
错误码的设计,可以借用http错误码+三位api自定义错误码 一共是6位数字,具体每个模块代表什么可以根据你自己的业务逻辑,定义不同数字,位数对应不同模块
对应错误格式如下
错误接口
package cn.soboys.springbootrestfulapi.common.error;
/**
* @author 公众号 程序员三时
* @version 1.0
* @date 2023/5/2 21:33
* @webSite https://github.com/coder-amiao
* 错误码接口,凡各模块错误码枚举类,皆须为此接口的子类型
*/
public interface ErrorCode {
Integer getCode();
String getMessage();
boolean getSuccess();
}
自定义错误实现枚举
package cn.soboys.springbootrestfulapi.common.error;
/**
* @author 公众号 程序员三时
* @version 1.0
* @date 2023/5/2 21:36
* @webSite https://github.com/coder-amiao
*/
public enum CommonErrorCode implements ErrorCode {
NOT_FOUND(false, 404, "接口不存在"),
FORBIDDEN(false, 403, "资源拒绝访问"),
UNAUTHORIZED(false, 401, "未认证(签名错误)"),
INTERNAL_SERVER_ERROR(false, 500, "服务网络不可用"),
PARAM_ERROR(false, 110001, "参数错误");
CommonErrorCode(Boolean success, Integer code, String message) {
this.success = success;
this.code = code;
this.message = message;
}
/**
* 响应是否成功
*/
private Boolean success;
/**
* 响应状态码
*/
private Integer code;
/**
* 响应信息
*/
private String message;
@Override
public Integer getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
@Override
public boolean getSuccess() {
return success;
}
}
全局异常错误处理
package cn.soboys.springbootrestfulapi.common.exception;
import cn.hutool.core.collection.CollectionUtil;
import cn.soboys.springbootrestfulapi.common.error.CommonErrorCode;
import cn.soboys.springbootrestfulapi.common.resp.R;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author 公众号 程序员三时
* @version 1.0
* @date 2023/4/29 00:21
* @webSite https://github.com/coder-amiao
* 统一异常处理器
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 通用异常处理方法
**/
@ExceptionHandler(Exception.class)
@ResponseBody
public R error(Exception e, WebRequest request) {
e.printStackTrace();
return R.setResult(CommonErrorCode.INTERNAL_SERVER_ERROR)
.request(request.getDescription(true))
.errorMsg(e.getMessage());
}
/**
* 处理 form data方式调用接口对象参数校验失败抛出的异常
*/
@ExceptionHandler(BindException.class)
@ResponseBody
public R BindExceptionHandler(BindException e) {
String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
return R.failure().code(CommonErrorCode.PARAM_ERROR.getCode()).message(message);
}
/**
* 处理Get请求中 验证路径中 单个参数请求失败抛出异常
* @param e
* @return
*/
@ExceptionHandler(ConstraintViolationException.class)
public R ConstraintViolationExceptionHandler(ConstraintViolationException e) {
String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
return R.failure().code(CommonErrorCode.PARAM_ERROR.getCode()).message(message);
}
/**
* 处理 json 请求体调用接口对象参数校验失败抛出的异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public R jsonParamsException(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
String msg=";";
for (FieldError fieldError : bindingResult.getFieldErrors()) {
msg = String.format("%s%s;", fieldError.getField(), fieldError.getDefaultMessage())+msg;
}
return R.failure().code(CommonErrorCode.PARAM_ERROR.getCode()).message(msg);
}
/**
* 自定义异常处理方法
*
* @param e
* @return
*/
@ExceptionHandler(BusinessException.class)
@ResponseBody
public R error(BusinessException e) {
e.printStackTrace();
return R.failure().message(e.getMessage()).code(e.getCode());
}
}
具体项目代码已经 同步到github 上,后续会完善更新一系列整合脚手架工具,能够开箱即用