错误响应
REST 服务的一个常见要求是在错误响应的正文中包含详细信息。Spring Framework 支持“HTTP API 问题详情”规范,https://datatracker.ietf.org/doc/html/rfc9457[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 路径设置。 -
对于内容协商,Jackson
HttpMessageConverter
在渲染ProblemDetail
时优先选择 "application/problem+json" 而不是 "application/json",并且在找不到兼容的媒体类型时也会回退到它。
要为 Spring MVC 异常和任何 ErrorResponseException
启用 RFC 9457 响应,请扩展 ResponseEntityExceptionHandler
并将其声明为 Spring 配置中的 @ControllerAdvice。该处理程序有一个 @ExceptionHandler
方法,用于处理任何 ErrorResponse
异常,其中包括所有内置的 Web 异常。您可以添加更多异常处理方法,并使用受保护的方法将任何异常映射到 ProblemDetail
。
您可以通过 MVC 配置 使用 WebMvcConfigurer
注册 ErrorResponse
拦截器。使用它来拦截任何 RFC 9457 响应并执行某些操作。
非标准字段
您可以通过两种方式使用非标准字段扩展 RFC 9457 响应。
其一,插入到 ProblemDetail
的 "properties" Map
中。当使用 Jackson 库时,Spring Framework 会注册 ProblemDetailJacksonMixin
,它确保此 "properties" Map
被解包并渲染为响应中的顶级 JSON 属性,同样,任何在反序列化过程中未知的属性也会插入到此 Map
中。
您还可以扩展 ProblemDetail
以添加专用的非标准属性。
ProblemDetail
中的复制构造函数允许子类从现有 ProblemDetail
轻松创建。这可以集中完成,例如,从 @ControllerAdvice
(例如 ResponseEntityExceptionHandler
)中,它将异常的 ProblemDetail
重新创建为带有附加非标准字段的子类。
自定义和国际化
自定义和国际化错误响应详情是一个常见的需求。 自定义 Spring MVC 异常的问题详情以避免暴露实现细节也是一个好习惯。本节描述了对此的支持。
ErrorResponse
公开“类型”、“标题”和“详情”的消息代码,以及“详情”字段的消息代码参数。ResponseEntityExceptionHandler
通过 MessageSource 解析这些内容,并相应地更新 ProblemDetail
字段。
消息代码的默认策略如下:
-
"type":
problemDetail.type.[完全限定异常类名]
-
"title":
problemDetail.title.[完全限定异常类名]
-
"detail":
problemDetail.[完全限定异常类名][后缀]
ErrorResponse
可以公开多个消息代码,通常会在默认消息代码后添加后缀。下表列出了 Spring MVC 异常的消息代码和参数:
异常 | 消息代码 | 消息代码参数 |
---|---|---|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) + ".parseError" |
|
|
(默认) |
|
|
(默认) + ".parseError" |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
与其他异常不同, |