错误响应

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

以下是此支持的主要抽象

  • ProblemDetail — RFC 9457 问题详细信息的表示;一个简单的容器,用于存储规范中定义的标准字段以及非标准字段。

  • ErrorResponse — 用于公开 HTTP 错误响应详细信息的契约,包括 HTTP 状态、响应头和 RFC 9457 格式的正文;这允许异常封装和公开它们如何映射到 HTTP 响应的详细信息。所有 Spring MVC 异常都实现了此接口。

  • ErrorResponseException — ErrorResponse 的基本实现,其他类可以使用它作为便捷的基类。

  • ResponseEntityExceptionHandler — @ControllerAdvice 的便捷基类,用于处理所有 Spring MVC 异常和任何 ErrorResponseException,并呈现带有正文的错误响应。

渲染

您可以从任何 @ExceptionHandler 或任何 @RequestMapping 方法返回 ProblemDetailErrorResponse 来渲染 RFC 9457 响应。这将按以下步骤处理

  • ProblemDetailstatus 属性决定 HTTP 状态。

  • ProblemDetailinstance 属性从当前 URL 路径设置,如果尚未设置。

  • 对于内容协商,Jackson HttpMessageConverter 在渲染 ProblemDetail 时优先选择“application/problem+json”而不是“application/json”,如果找不到兼容的媒体类型,也会回退到它。

要为 Spring WebFlux 异常和任何 ErrorResponseException 启用 RFC 9457 响应,请扩展 ResponseEntityExceptionHandler 并将其声明为 Spring 配置中的 @ControllerAdvice。处理程序有一个 @ExceptionHandler 方法,用于处理任何 ErrorResponse 异常,其中包括所有内置的 Web 异常。您可以添加更多异常处理方法,并使用受保护的方法将任何异常映射到 ProblemDetail

非标准字段

您可以通过两种方式之一扩展 RFC 9457 响应以包含非标准字段。

一种是插入 ProblemDetail 的“properties” Map 中。当使用 Jackson 库时,Spring 框架会注册 ProblemDetailJacksonMixin,确保此“properties” Map 被解包并作为顶级 JSON 属性渲染到响应中,同样,反序列化期间的任何未知属性都会插入到此 Map 中。

您也可以扩展ProblemDetail以添加专用的非标准属性。ProblemDetail中的复制构造函数允许子类从现有的ProblemDetail轻松创建。这可以在中心完成,例如,从@ControllerAdvice(例如ResponseEntityExceptionHandler)重新创建异常的ProblemDetail为具有附加非标准字段的子类。

自定义和国际化

自定义和国际化错误响应详细信息是一个常见的需求。为 Spring MVC 异常自定义问题详细信息也是一个好习惯,以避免泄露实现细节。本节介绍对此的支持。

ErrorResponse 公开“type”、“title”和“detail”的消息代码,以及“detail”字段的消息代码参数。ResponseEntityExceptionHandler 通过 MessageSource 解析这些代码,并相应地更新相应的 ProblemDetail 字段。

消息代码的默认策略如下

  • "type": problemDetail.type.[完全限定的异常类名]

  • "title": problemDetail.title.[完全限定的异常类名]

  • "detail": problemDetail.[完全限定的异常类名][后缀]

ErrorResponse 可能公开多个消息代码,通常在默认消息代码中添加后缀。下表列出了 Spring MVC 异常的消息代码和参数

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

AsyncRequestTimeoutException

(默认)

ConversionNotSupportedException

(默认)

{0} 属性名称,{1} 属性值

HandlerMethodValidationException

(默认)

{0} 列出所有验证错误。每个错误的消息代码和参数也通过 MessageSource 解析。

HttpMediaTypeNotAcceptableException

(默认)

{0} 支持的媒体类型列表

HttpMediaTypeNotAcceptableException

(默认) + ".parseError"

HttpMediaTypeNotSupportedException

(默认)

{0} 不支持的媒体类型,{1} 支持的媒体类型列表

HttpMediaTypeNotSupportedException

(默认) + ".parseError"

HttpMessageNotReadableException

(默认)

HttpMessageNotWritableException

(默认)

HttpRequestMethodNotSupportedException

(默认)

{0} 当前 HTTP 方法,{1} 支持的 HTTP 方法列表

MethodArgumentNotValidException

(默认)

{0} 全局错误列表,{1} 字段错误列表。每个错误的消息代码和参数也会通过 MessageSource 解析。

MissingRequestHeaderException

(默认)

{0} 头部名称

MissingServletRequestParameterException

(默认)

{0} 请求参数名称

MissingMatrixVariableException

(默认)

{0} 矩阵变量名称

MissingPathVariableException

(默认)

{0} 路径变量名称

MissingRequestCookieException

(默认)

{0} Cookie 名称

MissingServletRequestPartException

(默认)

{0} 部分名称

NoHandlerFoundException

(默认)

NoResourceFoundException

(默认)

TypeMismatchException

(默认)

{0} 属性名称,{1} 属性值

UnsatisfiedServletRequestParameterException

(默认)

{0} 参数条件列表

与其他异常不同,MethodArgumentValidExceptionHandlerMethodValidationException 的消息参数基于 MessageSourceResolvable 错误列表,这些错误也可以通过 MessageSource 资源包进行自定义。有关更多详细信息,请参阅 自定义验证错误

客户端处理

客户端应用程序可以使用 WebClient 时捕获 WebClientResponseException,或使用 RestTemplate 时捕获 RestClientResponseException,并使用它们的 getResponseBodyAs 方法将错误响应主体解码为任何目标类型,例如 ProblemDetailProblemDetail 的子类。