|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
错误响应
REST 服务的一个常见需求是在错误响应的正文中包含详细信息。Spring 框架支持“HTTP API 的问题详情”规范,RFC 7807。
以下是对此支持的主要抽象:
-
ProblemDetail— RFC 7807 问题详情的表示形式;一个简单的容器, 既包含规范中定义的标准字段,也包含非标准字段。 -
ErrorResponse— 用于公开 HTTP 错误响应详细信息的契约,包括 HTTP 状态、响应头以及符合 RFC 7807 格式的响应体;这使得异常能够封装并公开其映射到 HTTP 响应的具体细节。所有 Spring MVC 异常均实现了该接口。 -
ErrorResponseException— 一个基本的ErrorResponse实现,其他类可将其用作便捷的基类。 -
ResponseEntityExceptionHandler— 一个便捷的基类,用于处理所有 Spring MVC 异常以及任何xref page的@ControllerAdvice,并渲染一个包含响应体的错误响应。
渲染
你可以从任意 ProblemDetail 或任意 ErrorResponse 方法中返回 @ExceptionHandler 或 @RequestMapping,以渲染符合 RFC 7807 规范的响应。该响应将按如下方式处理:
-
status的ProblemDetail属性决定了 HTTP 状态。 -
如果尚未设置,
instance的ProblemDetail属性将从当前 URL 路径进行设置。 -
在内容协商过程中,当渲染
HttpMessageConverter时,Jackson 的ProblemDetail会优先选择 “application/problem+json” 而非 “application/json”,并且在未找到兼容的媒体类型时也会回退到该类型。
要为 Spring WebFlux 异常以及任何 ErrorResponseException 启用 RFC 7807 响应,请继承 ResponseEntityExceptionHandler 并在 Spring 配置中将其声明为 @ControllerAdvice。该处理器包含一个 @ExceptionHandler 方法,用于处理所有 ErrorResponse 异常(包括所有内置的 Web 异常)。您可以添加更多的异常处理方法,并使用一个受保护的方法将任意异常映射为 ProblemDetail。
非标准字段
您可以通过以下两种方式之一,在 RFC 7807 响应中添加非标准字段。
其一,插入到 Map 的“properties”ProblemDetail 中。当使用 Jackson 库时,Spring Framework 会注册 ProblemDetailJacksonMixin,以确保该“properties”Map 在响应中被展开并作为顶层 JSON 属性进行渲染;同样地,在反序列化过程中,任何未知属性也会被插入到该 Map 中。
你也可以扩展 ProblemDetail 以添加专用的非标准属性。
ProblemDetail 中的复制构造函数允许子类轻松地从现有的 ProblemDetail 创建实例。
这可以集中完成,例如通过一个 @ControllerAdvice(如 ResponseEntityExceptionHandler)
将异常中的 ProblemDetail 重新创建为一个包含额外非标准字段的子类。
国际化
国际化错误响应详情是一种常见需求,而针对 Spring MVC 异常自定义问题详情也是一种良好实践。对此的支持方式如下:
-
每个
ErrorResponse都公开了一个消息代码(message code)和参数,用于通过 MessageSource 解析“detail”字段。 实际的消息代码值使用占位符进行参数化,例如"HTTP method {0} not supported",并将根据参数进行展开。 -
每个
ErrorResponse还会公开一个消息代码,用于解析“title”字段。 -
ResponseEntityExceptionHandler使用消息代码和参数来解析“detail”(详情)和“title”(标题)字段。
默认情况下,“detail”字段的消息代码为“problemDetail.”加上异常类的完整限定名。某些异常可能会暴露额外的消息代码,此时会在默认消息代码后添加一个后缀。下表列出了 Spring MVC 异常的消息参数和代码:
| 异常 | 消息代码 | 消息代码参数 |
|---|---|---|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认)+ ".parseError" |
|
|
(默认) |
|
|
(默认)+ ".parseError" |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
|
(默认) |
|
默认情况下,“title”字段的消息代码为“problemDetail.title.”加上异常类的完整限定名。
客户端处理
当使用 WebClientResponseException 时,客户端应用程序可以捕获 WebClient;
当使用 RestClientResponseException 时,则可捕获 RestTemplate,
并利用它们的 getResponseBodyAs 方法将错误响应体解码为任意目标类型,
例如 ProblemDetail 或其子类。