https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-ann-rest-exceptions.html
REST服务的一个常见需求是在错误响应的主体中包含详细信息。Spring框架支持“HTTP API的问题细节”规范,即RFC 7807。
以下是支持RFC 7807的主要抽象:
- ProblemDetail — RFC 7807问题细节的表示;它是一个简单的容器,既可以包含规范中定义的标准字段,也可以包含非标准字段。
- ErrorResponse — 用于公开HTTP错误响应细节的约定,包括HTTP状态、响应头和遵循RFC 7807格式的响应体;这使得异常能够封装和公开它们如何映射到HTTP响应的细节。所有的Spring MVC异常都实现了这个约定。
- ErrorResponseException — 一个基本的ErrorResponse实现,其他类可以作为方便的基类来使用。
- ResponseEntityExceptionHandler — 一个@ControllerAdvice的便捷基类,用于处理所有的Spring MVC异常以及任何ErrorResponseException,并生成具有响应体的错误响应。
渲染(Render)
可以从任何@ExceptionHandler或任何@RequestMapping方法中返回ProblemDetail或ErrorResponse,以呈现RFC 7807响应。处理过程如下:
可以从任何@ExceptionHandler方法或任何@RequestMapping方法中返回ProblemDetail或ErrorResponse,以生成RFC 7807响应。处理过程如下:
- ProblemDetail的status属性决定了HTTP状态。
- 如果尚未设置,ProblemDetail的instance属性会从当前URL路径中设置。
- 在内容协商方面,当渲染ProblemDetail时,Jackson HttpMessageConverter会优先选择"application/problem+json"而不是"application/json",如果找不到兼容的媒体类型,它也会回退到"application/problem+json"。
要启用Spring WebFlux异常以及任何ErrorResponseException的RFC 7807响应,需要扩展ResponseEntityExceptionHandler并将其在Spring配置中声明为@ControllerAdvice。处理器有一个@ExceptionHandler方法,用于处理任何ErrorResponse异常,这包括所有内置的Web异常。可以添加更多的异常处理方法,并使用一个受保护的方法将任何异常映射为ProblemDetail。
非标准字段
可以通过以下两种方式之一扩展RFC 7807响应以包含非标准字段。
一种方法是,将非标准字段插入到ProblemDetail的“properties”映射中。当使用Jackson库时,Spring框架会注册ProblemDetailJacksonMixin,以确保这个“properties”映射在响应中以顶级JSON属性的形式展开和呈现,同样地,在反序列化过程中的任何未知属性也会被插入到这个映射中。
还可以扩展ProblemDetail以添加专用的非标准属性。ProblemDetail中的复制构造函数允许子类从现有的ProblemDetail轻松创建实例。这可以在中央位置完成,例如从@ControllerAdvice(如ResponseEntityExceptionHandler)中,它将异常的ProblemDetail重新创建为带有额外非标准字段的子类。
定制与国际化(i18n)
定制和国际化错误响应详情是一个常见的需求。同时,为了避免暴露实现细节,对Spring MVC异常的问题详情进行定制也是一个好的做法。
ErrorResponse会公开“type”(类型)、“title”(标题)和“detail”(详情)的消息代码,以及“detail”字段的消息代码参数。ResponseEntityExceptionHandler会通过MessageSource来解析这些消息代码,并相应地更新对应的ProblemDetail字段。
消息代码的默认策略遵循以下模式:
problemDetail.[type|title|detail].[fully qualified exception class name]
ErrorResponse可能会暴露多个消息代码,通常是在默认消息代码后添加后缀。下面的表格列出了Spring MVC异常的消息代码及其参数:
与其他异常不同,MethodArgumentValidException和HandlerMethodValidationException的消息参数是基于一个MessageSourceResolvable错误列表的,这些错误也可以通过MessageSource资源捆绑包进行定制。
客户端处理
当使用WebClient时,客户端应用程序可以捕获WebClientResponseException异常;而当使用RestTemplate时,则可以捕获RestClientResponseException异常。通过调用这些异常的getResponseBodyAs方法,客户端应用程序可以将错误响应体解码为任何目标类型,例如ProblemDetail或其子类。这样,应用程序就能以结构化的方式处理错误响应,从而更好地理解和处理发生的错误。