错误响应
REST服务的一个常见需求是在错误响应的正文中包含详细信息。Spring框架支持“HTTP API的问题详细信息”规范,RFC 9457。
以下是该支持的主要抽象概念:
-
ProblemDetail— RFC 9457 问题详情的表示;一个用于容纳规范中定义的标准字段以及非标准字段的简单容器。 -
ErrorResponse— 约定用于暴露HTTP错误响应的详细信息,包括HTTP状态、响应头以及符合RFC 9457格式的响应体;这使得异常能够封装并暴露其映射到HTTP响应的细节。所有Spring WebFlux异常都实现了此约定。 -
ErrorResponseException— 基础ErrorResponse实现,其他人可用作便捷基类。 -
ResponseEntityExceptionHandler——一个便捷的基类,用于处理所有Spring WebFlux异常、 任何ErrorResponseException异常,并通过响应体渲染错误结果的 @ControllerAdvice。
渲染
您可以从任意 @ExceptionHandler 或任意 @RequestMapping 方法返回 ProblemDetail 或 ErrorResponse,以生成 RFC 9457 响应。其处理方式如下:
-
ProblemDetail的status属性决定了 HTTP 状态。 -
如果尚未设置,
ProblemDetail的instance属性将从当前 URL 路径设置。 -
Jackson JSON和XML消息转换器分别使用 "application/problem+json" 或 "application/problem+xml" 作为
ProblemDetail的可生产媒体类型,以确保它们在内容协商中受到优先考虑。
要为 Spring WebFlux 异常以及任何
ErrorResponseException 启用 RFC 9457 响应,请继承 ResponseEntityExceptionHandler 并在 Spring 配置中将其声明为
@ControllerAdvice。该处理器包含一个 @ExceptionHandler 方法,用于处理任何 ErrorResponse 异常,其中包括所有内置的 Web 异常。您可以添加更多的异常处理方法,并使用受保护的方法将任何异常映射到 ProblemDetail。
您可以通过 WebFlux 配置 使用 ErrorResponse 注册拦截器。利用此功能拦截任何RFC 9457响应并采取相应操作。
非标准字段
你可以通过以下两种方式之一,使用非标准字段扩展 RFC 9457 响应。
一、将数据插入到ProblemDetail的"properties"Map中。使用Jackson库时,Spring框架会注册ProblemDetailJacksonMixin,
确保该"properties"Map被展开并作为顶级JSON属性呈现在响应中,
同样地,在反序列化过程中任何未知属性也会被插入到此Map中。
您也可以扩展 ProblemDetail 以添加专用的非标准属性。
ProblemDetail 中的复制构造函数使得子类能够轻松地从现有 ProblemDetail 创建。这可以集中进行,例如,从一个
@ControllerAdvice,如 ResponseEntityExceptionHandler,将异常的
ProblemDetail 重新创建为具有额外非标准字段的子类。
在Spring Boot中,spring.webflux.problemdetails.enabled属性会自动配置一个ResponseEntityExceptionHandler,用于以问题详情的形式处理内置异常。在这种情况下,如果您想接管特定内置异常的处理,可能更倾向于创建另一个@ControllerAdvice,而不是扩展ResponseEntityExceptionHandler。您需要确保您的处理器排序在Spring Boot配置的处理器(其顺序为0)之前。 |
自定义和国际化
自定义和国际化错误响应详情是一个常见的需求。 同样,为 Spring WebFlux 异常自定义问题详情也是一种良好的实践, 可避免暴露实现细节。本节介绍对此的支持。
一个ErrorResponse暴露了用于"type"、"title"和"detail"的消息代码,以及为"detail"字段的消息代码参数。ResponseEntityExceptionHandler通过MessageSource
解析这些,并相应地更新对应的ProblemDetail字段。
默认的消息代码策略遵循以下模式:
problemDetail.[type|title|detail].[fully qualified exception class name]
一个 ErrorResponse 可能会暴露多个消息代码,通常是在默认消息代码后添加一个后缀。
下表列出了 Spring WebFlux 异常的消息代码及其参数:
| 异常 | 消息代码 | 消息代码参数值 |
|---|---|---|
|
默认 |
|
|
默认 |
|
|
默认 |
|
|
默认 |
|
|
(default) + ".parseError" |
|
|
默认 |
|
|
默认 |
|
|
(default) + ".parseError" |
|
|
默认 |
|
|
默认 |
|
|
默认 |
|
与其他异常不同,WebExchangeBindException 和 HandlerMethodValidationException 的消息参数基于一个 MessageSourceResolvable 错误列表,该列表也可以通过
MessageSource
资源包进行自定义。更多详细信息,请参见
自定义验证错误。 |
客户端处理
客户端应用在使用 WebClient 时可以捕获 WebClientResponseException,或在使用 RestTemplate 时捕获 RestClientResponseException,并通过其
getResponseBodyAs 方法将错误响应体解码为任意目标类型,例如
ProblemDetail 或 ProblemDetail 的子类。