对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

错误响应

REST 服务的一个常见需求是在错误响应的正文中包含详细信息。Spring 框架支持“HTTP API 的问题详情”规范,RFC 9457spring-doc.cadn.net.cn

以下是对此支持的主要抽象:spring-doc.cadn.net.cn

  • ProblemDetail — RFC 9457 问题详情的表示形式;一个简单的容器, 既包含规范中定义的标准字段,也包含非标准字段。spring-doc.cadn.net.cn

  • ErrorResponse — 用于公开 HTTP 错误响应详细信息的契约,包括 HTTP 状态、响应头以及符合 RFC 9457 格式的响应体;这使得异常能够封装并公开其映射到 HTTP 响应的详细信息。所有 Spring WebFlux 异常均实现了该接口。spring-doc.cadn.net.cn

  • ErrorResponseException — 一个基本的 ErrorResponse 实现,其他类可将其用作便捷的基类。spring-doc.cadn.net.cn

  • ResponseEntityExceptionHandler — 一个便捷的基类,用于处理所有 Spring WebFlux 异常以及任何 xref page@ControllerAdvice,并渲染一个包含响应体的错误响应。spring-doc.cadn.net.cn

渲染

你可以从任意 ProblemDetail 或任意 ErrorResponse 方法中返回 @ExceptionHandler@RequestMapping,以渲染符合 RFC 9457 规范的响应。该响应将按如下方式处理:spring-doc.cadn.net.cn

  • statusProblemDetail 属性决定了 HTTP 状态。spring-doc.cadn.net.cn

  • 如果尚未设置,instanceProblemDetail 属性将从当前 URL 路径进行设置。spring-doc.cadn.net.cn

  • Jackson JSON 和 XML 消息转换器分别使用 "application/problem+json" 或 "application/problem+xml" 作为 ProblemDetail 的可生成媒体类型,以确保在内容协商时优先选用它们。spring-doc.cadn.net.cn

要为 Spring WebFlux 异常以及任何 ErrorResponseException 启用 RFC 9457 响应,请继承 ResponseEntityExceptionHandler 并在 Spring 配置中将其声明为 @ControllerAdvice。该处理器包含一个 @ExceptionHandler 方法,用于处理所有 ErrorResponse 异常(包括所有内置的 Web 异常)。您可以添加更多的异常处理方法,并使用一个受保护的方法将任意异常映射到 ProblemDetailspring-doc.cadn.net.cn

您可以通过WebFlux 配置使用config.html注册WebFluxConfigurer拦截器。利用该机制可拦截任何符合 RFC 9457 的响应并执行某些操作。spring-doc.cadn.net.cn

非标准字段

您可以通过以下两种方式之一,使用非标准字段扩展 RFC 9457 响应。spring-doc.cadn.net.cn

其一,插入到 Map 的“properties”ProblemDetail 中。当使用 Jackson 库时,Spring Framework 会注册 ProblemDetailJacksonMixin,以确保该“properties”Map 在响应中被展开并作为顶层 JSON 属性进行渲染;同样地,在反序列化过程中,任何未知属性也会被插入到该 Map 中。spring-doc.cadn.net.cn

你也可以扩展 ProblemDetail 以添加专用的非标准属性。 ProblemDetail 中的复制构造函数允许子类轻松地从现有的 ProblemDetail 创建实例。 例如,这可以在一个中心位置完成,比如通过 @ControllerAdvice(如 ResponseEntityExceptionHandler) 将异常中的 ProblemDetail 重新创建为一个包含额外非标准字段的子类。spring-doc.cadn.net.cn

自定义与国际化 (i18n)

自定义和国际化错误响应详情是一项常见需求。 同时,为 Spring WebFlux 异常自定义问题详情也是一种良好实践, 以避免暴露实现细节。本节将介绍对此的支持。spring-doc.cadn.net.cn

ErrorResponse 会暴露用于“type”、“title”和“detail”的消息代码,以及“detail”字段的消息代码参数。ResponseEntityExceptionHandler 通过 MessageSource 解析这些消息代码,并相应地更新 ProblemDetail 中对应的字段。spring-doc.cadn.net.cn

消息代码的默认策略遵循以下模式:spring-doc.cadn.net.cn

problemDetail.[type|title|detail].[fully qualified exception class name]spring-doc.cadn.net.cn

ErrorResponse 可能会暴露多个消息代码,通常是在默认消息代码后添加一个后缀。下表列出了 Spring WebFlux 异常对应的消息代码及其参数:spring-doc.cadn.net.cn

异常 消息代码 消息代码参数

HandlerMethodValidationExceptionspring-doc.cadn.net.cn

(默认)spring-doc.cadn.net.cn

{0} 列出所有验证错误。 每个错误的消息代码和参数也通过 MessageSource 进行解析。spring-doc.cadn.net.cn

MethodNotAllowedExceptionspring-doc.cadn.net.cn

(默认)spring-doc.cadn.net.cn

{0} 当前的 HTTP 方法,{1} 支持的 HTTP 方法列表spring-doc.cadn.net.cn

MissingRequestValueExceptionspring-doc.cadn.net.cn

(默认)spring-doc.cadn.net.cn

{0} 表示该值的标签(例如,“请求头”、“Cookie 值”……),{1} 表示该值的名称spring-doc.cadn.net.cn

NotAcceptableStatusExceptionspring-doc.cadn.net.cn

(默认)spring-doc.cadn.net.cn

{0} 支持的媒体类型列表spring-doc.cadn.net.cn

NotAcceptableStatusExceptionspring-doc.cadn.net.cn

(默认)+ ".parseError"spring-doc.cadn.net.cn

ServerErrorExceptionspring-doc.cadn.net.cn

(默认)spring-doc.cadn.net.cn

{0} 提供给类构造函数的失败原因spring-doc.cadn.net.cn

UnsupportedMediaTypeStatusExceptionspring-doc.cadn.net.cn

(默认)spring-doc.cadn.net.cn

{0} 不支持的媒体类型,{1} 支持的媒体类型列表spring-doc.cadn.net.cn

UnsupportedMediaTypeStatusExceptionspring-doc.cadn.net.cn

(默认)+ ".parseError"spring-doc.cadn.net.cn

UnsatisfiedRequestParameterExceptionspring-doc.cadn.net.cn

(默认)spring-doc.cadn.net.cn

{0} 参数条件列表spring-doc.cadn.net.cn

WebExchangeBindExceptionspring-doc.cadn.net.cn

(默认)spring-doc.cadn.net.cn

{0} 表示全局错误列表,{1} 表示字段错误列表。 每个错误的消息代码和参数也通过 MessageSource 进行解析。spring-doc.cadn.net.cn

与其他异常不同,WebExchangeBindExceptionHandlerMethodValidationException 的消息参数基于一个 MessageSourceResolvable 错误列表,这些错误也可以通过 MessageSource 资源包进行自定义。更多详情请参见 自定义验证错误

客户端处理

当使用 WebClientResponseException 时,客户端应用程序可以捕获 WebClient; 当使用 RestClientResponseException 时,则可捕获 RestTemplate, 并利用它们的 getResponseBodyAs 方法将错误响应体解码为任意目标类型, 例如 ProblemDetail 或其子类。spring-doc.cadn.net.cn