更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞👍收藏⭐评论✍
重学SpringBoot3-Problemdetails
- Problem Details的概念
- ProblemDetails配置类
- 在Spring Boot 3中使用Problem Details
- 未配置Problem Details
- 配置Problem Details
- 自定义异常处理器
- 自定义Problem Details
- 自定义异常继承 ErrorResponseException
- 实践建议
随着 Spring Boot 3 的发布,Spring Framework 6 继续在提升开发者体验和应用性能方面迈出重要步伐。在众多引人注目的新特性中,对 Problem Details(问题详情)的支持尤为值得关注。这一特性基于 RFC 7807 标准,旨在为 HTTP API 提供一种标准化的错误响应格式。本文将深入探讨 Spring Boot 3 中 Problem Details 的概念、应用及其对微服务架构的潜在影响。
Problem Details的概念
RFC 7807: https://www.rfc-editor.org/rfc/rfc7807
在 RESTful 架构的 API 设计中,如何有效地表达错误信息一直是一个挑战。RFC 7807 定义的 Problem Details 机制提供了一种标准化的方式,通过具体、一致的格式来传达错误信息,使得客户端能够更容易地理解和处理 API 响应中的错误。
一个典型的 Problem Details 响应包含以下几个基本字段:
type
:一个URI,指向错误类型的详细描述文档(可选)。title
:简短、人类可读的错误概述。status
:HTTP状态码。detail
:人类可读的解释,提供更多关于问题的细节。instance
:指向导致问题的具体请求或实例的URI(可选)。
ProblemDetails配置类
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.ProblemDetailsErrorHandlingConfiguration
当满足以下条件时,这个 Problem Details 配置类会被加载:
- 属性
spring.mvc.problemdetails.enabled
的值为 true; - 没有其他相同类型的 Bean 被定义。
这个配置类中,定义了一个名为 problemDetailsExceptionHandler
的方法,该方法返回一个新的 ProblemDetailsExceptionHandler
类型实例,是一个标注了 @ControllerAdvice
集中处理系统异常。这个实例是继承自 ResponseEntityExceptionHandler
,用于处理控制器中的异常,并返回相应的错误信息。
当前版本支持的异常类型,即如果系统出现以下异常,会被 SpringBoot 支持以 RFC 7807
规范方式返回错误数据:
@ExceptionHandler({HttpRequestMethodNotSupportedException.class,HttpMediaTypeNotSupportedException.class,HttpMediaTypeNotAcceptableException.class,MissingPathVariableException.class,MissingServletRequestParameterException.class,MissingServletRequestPartException.class,ServletRequestBindingException.class,MethodArgumentNotValidException.class,HandlerMethodValidationException.class,NoHandlerFoundException.class,NoResourceFoundException.class,AsyncRequestTimeoutException.class,ErrorResponseException.class,MaxUploadSizeExceededException.class,ConversionNotSupportedException.class,TypeMismatchException.class,HttpMessageNotReadableException.class,HttpMessageNotWritableException.class,MethodValidationException.class,BindException.class})
在Spring Boot 3中使用Problem Details
Spring Boot 3 中引入了对 Problem Details 的支持,使得开发者可以轻松地在自己的应用中应用这一标准。通过使用 Spring Boot 提供的工具和注解,你可以快速地为你的 API 添加对 Problem Details 的支持,从而提升 API 的可用性和易用性。
未配置Problem Details
例如对一个 仅支持 POST 请求的接口采用 GET 方式调用,如果是 HTML 页面展示则会出现白页:
如果是获取 JSON 则返回如下信息:
配置Problem Details
在 Spring Boot 3 应用中,首先确保你的项目引入了 Spring Boot 的 Web 模块。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
配置文件中开启 Problem Details:
spring.mvc.problemdetails.enabled=true
自定义异常处理器
可以通过定义异常处理器来使用 Problem Details,并且支持自定义异常。
首先看下,如果系统发生了不支持的异常类型,就不能被处理成符合 Problem Details 标准的响应:
java.lang.ArithmeticException: / by zero
接下来,通过定义异常处理器支持这个除零异常:
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.net.URI;/*** @author CoderJia* @create 2024/03/15 10:00* @Description**/
@RestControllerAdvice(basePackages = "com.coderjia.springboot304web.controller")
public class GlobalExceptionHandler {@ExceptionHandler(ArithmeticException.class)public ProblemDetail handleCustomException(ArithmeticException ex) {ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage());problemDetail.setTitle("服务器发生异常");problemDetail.setType(URI.create("https://coderjia.cn/errors/xxx"));return problemDetail;}
}
发生此类异常显示如下:
自定义Problem Details
除了标准字段 type
、title
、status
、detail
和 instance
外,还可以通过 setProperty()
自定义一些属性:
@ExceptionHandler(ArithmeticException.class)public ProblemDetail handleCustomException(ArithmeticException ex) {ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage());problemDetail.setTitle("服务器发生异常");problemDetail.setType(URI.create("https://coderjia.cn/errors/xxx"));problemDetail.setProperty("errorCategory", "Generic");problemDetail.setProperty("timestamp", Instant.now());return problemDetail;}
自定义异常继承 ErrorResponseException
除了以上方法,还可以直接继承 ErrorResponseException
,然后直接抛出该异常,会被处理成符合 Problem Details 标准的响应。
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.ErrorResponseException;import java.net.URI;
import java.time.Instant;/*** @author CoderJia* @create 2024/03/15 9:39* @Description**/
public class DivideByZeroException extends ErrorResponseException {public DivideByZeroException(String customMsg) {super(HttpStatus.NOT_FOUND, asProblemDetail(customMsg), null);}private static ProblemDetail asProblemDetail(String customMsg) {ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, customMsg);problemDetail.setTitle("除零异常");problemDetail.setType(URI.create("https://coderjia.cn/errors/xxx"));problemDetail.setProperty("timestamp", Instant.now());return problemDetail;}
}
实践建议
使用 Problem Details 的主要优点是提高了 API 错误处理的一致性和可理解性。通过提供标准化的错误响应格式,客户端开发者可以更容易地理解和处理 API 返回的错误信息。在实践中,建议为你的 API 定义一套统一的错误类型,并为这些错误类型提供详细的文档。这样,当 API 返回错误时,客户端开发者可以通过 type
字段提供的 URI 访问到关于错误类型的详细说明,从而更好地理解和处理错误。