错误响应
对于 REST 服务来说,在错误响应体中包含详细信息是一个常见的需求。Spring Framework 支持“HTTP API 的问题详情”规范,RFC 9457。
以下是此支持的主要抽象
-
ProblemDetail
— RFC 9457 问题详情的表示;一个简单的容器,包含规范中定义的标准字段和非标准字段。 -
ErrorResponse
— 公开 HTTP 错误响应详情的契约,包括 HTTP 状态、响应头和 RFC 9457 格式的响应体;这使得异常能够封装并公开它们如何映射到 HTTP 响应的详情。所有 Spring MVC 异常都实现了此接口。 -
ErrorResponseException
— 基本的ErrorResponse
实现,其他类可以方便地将其用作基类。 -
ResponseEntityExceptionHandler
— @ControllerAdvice 的便捷基类,用于处理所有 Spring MVC 异常以及任何ErrorResponseException
,并渲染带响应体的错误响应。
渲染
您可以从任何 @ExceptionHandler
或 @RequestMapping
方法返回 ProblemDetail
或 ErrorResponse
以渲染 RFC 9457 响应。处理过程如下
-
ProblemDetail
的status
属性决定 HTTP 状态。 -
ProblemDetail
的instance
属性会在未设置时从当前 URL 路径设置。 -
对于内容协商,在渲染
ProblemDetail
时,JacksonHttpMessageConverter
优先选择“application/problem+json”而非“application/json”,如果找不到兼容的媒体类型,也会回退到它。
要为 Spring MVC 异常和任何 ErrorResponseException
启用 RFC 9457 响应,请扩展 ResponseEntityExceptionHandler
并将其声明为 Spring 配置中的 @ControllerAdvice。该 handler 有一个 @ExceptionHandler
方法,用于处理任何 ErrorResponse
异常,包括所有内置的 Web 异常。您可以添加更多异常处理方法,并使用一个保护方法将任何异常映射到 ProblemDetail
。
您可以通过带有 WebMvcConfigurer
的 MVC 配置注册 ErrorResponse
拦截器。使用它来拦截任何 RFC 9457 响应并执行一些操作。
非标准字段
您可以通过以下两种方式之一使用非标准字段扩展 RFC 9457 响应。
其一,插入到 ProblemDetail
的“properties” Map
中。使用 Jackson 库时,Spring Framework 注册了 ProblemDetailJacksonMixin
,它确保将此“properties” Map
解包并作为顶级 JSON 属性渲染到响应中,同样,反序列化期间任何未知属性也会插入到此 Map
中。
您也可以扩展 ProblemDetail
以添加专用的非标准属性。ProblemDetail
中的复制构造器允许子类轻松地从现有 ProblemDetail
创建新实例。这可以集中处理,例如,从像 ResponseEntityExceptionHandler
这样的 @ControllerAdvice
中实现,它将异常的 ProblemDetail
重建为一个包含额外非标准字段的子类实例。
定制和国际化 (i18n)
定制和国际化错误响应详情是一个常见的需求。定制 Spring MVC 异常的问题详情以避免暴露实现细节也是一个好的实践。本节介绍对此的支持。
ErrorResponse
公开针对“type”、“title”和“detail”的消息代码,以及针对“detail”字段的消息代码参数。ResponseEntityExceptionHandler
通过 MessageSource 解析这些代码,并相应地更新对应的 ProblemDetail
字段。
消息代码的默认策略如下
-
“type”:
problemDetail.type.[异常类的完全限定名]
-
“title”:
problemDetail.title.[异常类的完全限定名]
-
“detail”:
problemDetail.[异常类的完全限定名][后缀]
ErrorResponse
可能公开多个消息代码,通常在默认消息代码后添加后缀。下表列出了 Spring MVC 异常的消息代码和参数
异常 | 消息代码 | 消息代码参数 |
---|---|---|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认)+ ".parseError" |
|
|
(默认) |
|
|
(默认)+ ".parseError" |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
与其他异常不同,MethodArgumentValidException 和 HandlerMethodValidationException 的消息参数基于 MessageSourceResolvable 错误列表,这些错误也可以通过 MessageSource 资源包进行定制。有关更多详情,请参阅定制验证错误。 |