Spring Boot REST API异常捕获最佳实践:处理JSON解析异常
这个问题在Spring Boot开发中太常见了!我来分享几个生产环境里验证过的最佳实践,帮你优雅处理这类异常:
1. 全局统一异常处理(核心方案)
Spring提供了@RestControllerAdvice和@ExceptionHandler注解,可以全局捕获并处理这类JSON解析异常,不用在每个Controller里重复写异常处理逻辑。
你可以创建一个全局异常处理器,专门处理HttpMessageNotReadableException(Spring会把底层的JsonParseException包装成这个异常),返回友好的错误响应给前端,而不是暴露底层的异常细节:
@RestControllerAdvice public class GlobalExceptionHandler { // 处理JSON解析格式错误、参数无法绑定的异常 @ExceptionHandler(HttpMessageNotReadableException.class) public ResponseEntity<ErrorResponse> handleJsonParseError(HttpMessageNotReadableException ex) { Throwable rootCause = ex.getRootCause(); String errorMsg; if (rootCause instanceof JsonParseException) { errorMsg = "请求JSON格式错误:" + rootCause.getMessage().split("\\(")[0]; // 简化错误信息,避免太技术化 } else { errorMsg = "请求参数格式不正确,请检查输入内容"; } ErrorResponse response = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), errorMsg); return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } // 顺便处理参数校验异常(比如字段为空、长度不符合要求) @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidationError(MethodArgumentNotValidException ex) { StringBuilder errorMsg = new StringBuilder(); ex.getBindingResult().getAllErrors().forEach(error -> { errorMsg.append(error.getDefaultMessage()).append("; "); }); ErrorResponse response = new ErrorResponse(HttpStatus.BAD_REQUEST.value(), errorMsg.toString()); return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } // 自定义标准化错误响应类 static class ErrorResponse { private int status; private String message; public ErrorResponse(int status, String message) { this.status = status; this.message = message; } // Getter和Setter(或者用Lombok的@Data简化) public int getStatus() { return status; } public void setStatus(int status) { this.status = status; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } }
2. 开启请求参数校验,提前拦截非法数据
光处理解析异常还不够,我们可以提前校验请求参数的合法性。给@RequestBody的参数加上@Valid注解,同时在Student类的字段上添加校验注解,比如@NotBlank、@Size等:
第一步:给Student类添加校验注解
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; // 如果是Spring Boot 2.x,用javax.validation.constraints.* @JsonIgnoreProperties(ignoreUnknown = true) // 后面会讲这个注解的作用 public class Student { @NotBlank(message = "用户名不能为空") private String username; @NotBlank(message = "密码不能为空") @Size(min = 6, message = "密码长度不能少于6位") private String password; // 其他字段、Getter和Setter }
第二步:在Controller方法里启用校验
@RequestMapping(method = RequestMethod.POST, value = "/student") public ResponseEntity<Void> addStudent(@Valid @RequestBody Student student) { student.setPassword(bCryptPasswordEncoder.encode(student.getPassword())); studentService.addStudent(student); return ResponseEntity.status(HttpStatus.CREATED).build(); }
这样如果前端传的JSON格式正确,但字段不符合业务要求(比如密码太短),会抛出MethodArgumentNotValidException,上面的全局处理器会捕获并返回明确的错误提示。
3. 配置Jackson容错,提高接口兼容性
有时候前端可能会传一些Student类里没有的字段,默认情况下Jackson会抛出异常。我们可以配置Jackson忽略未知字段,或者允许一些容错行为:
方式一:通过配置文件(application.yml)全局配置
spring: jackson: deserialization: fail-on-unknown-properties: false # 忽略未知字段 accept-empty-string-as-null-object: true # 允许空字符串转为null
方式二:在实体类上单独配置
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) public class Student { // 字段... }
这样即使前端多传了字段,接口也不会报错,只会忽略这些无关字段,提高接口的兼容性。
4. 返回标准化的错误响应
不管是解析异常还是参数校验异常,都返回统一格式的错误响应(比如上面的ErrorResponse),这样前端可以统一处理错误逻辑,不用适配不同的错误格式。
内容的提问来源于stack exchange,提问作者babastyle
相关产品推荐
相关产品推荐

