错误响应

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 MVC异常都实现了此约定。spring-doc.cadn.net.cn

  • ErrorResponseException — 基础 ErrorResponse 实现,其他人可用作便捷基类。spring-doc.cadn.net.cn

  • ResponseEntityExceptionHandler——处理所有Spring MVC异常和任何ErrorResponseException@ControllerAdvice便捷基类,并渲染包含正文的错误响应。spring-doc.cadn.net.cn

渲染

您可以从任意 @ExceptionHandler 或任意 @RequestMapping 方法返回 ProblemDetailErrorResponse,以生成 RFC 9457 响应。其处理方式如下:spring-doc.cadn.net.cn

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

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

  • Jackson JSON和XML编解码器分别使用 "application/problem+json" 或 "application/problem+xml" 作为ProblemDetail的可生产媒体类型,以确保它们在内容协商中受到优先考虑。spring-doc.cadn.net.cn

为了使Spring MVC异常以及任何 ErrorResponseException 支持RFC 9457响应,需要扩展 ResponseEntityExceptionHandler 并在Spring配置中声明为 @ControllerAdvice。该处理器有一个 @ExceptionHandler 方法,用于处理任何 ErrorResponse 异常,这包括所有内置的Web异常。您可以添加更多的异常处理方法,并使用受保护的方法将任何异常映射到一个 ProblemDetailspring-doc.cadn.net.cn

您可以通过 MVC 配置 使用 ErrorResponse 注册拦截器。利用它来拦截任何 RFC 9457 响应并采取相应操作。spring-doc.cadn.net.cn

非标准字段

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

一、将数据插入到ProblemDetail的"properties"Map中。使用Jackson库时,Spring框架会注册ProblemDetailJacksonMixin, 确保该"properties"Map被展开并作为顶级JSON属性呈现在响应中, 同样地,在反序列化过程中任何未知属性也会被插入到此Map中。spring-doc.cadn.net.cn

您也可以扩展 ProblemDetail 以添加专用的非标准属性。 ProblemDetail 中的复制构造函数使得子类能够轻松地从现有 ProblemDetail 创建。这可以集中进行,例如,从一个 @ControllerAdvice,如 ResponseEntityExceptionHandler,将异常的 ProblemDetail 重新创建为具有额外非标准字段的子类。spring-doc.cadn.net.cn

在Spring Boot中,spring.mvc.problemdetails.enabled属性会自动配置一个ResponseEntityExceptionHandler,用于以问题详情的形式处理内置异常。在这种情况下,如果您想接管特定内置异常的处理,可能更倾向于创建另一个@ControllerAdvice,而不是扩展ResponseEntityExceptionHandler。您需要确保您的处理器排序在Spring Boot配置的处理器(其顺序为0)之前。

自定义和国际化

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

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

消息代码的默认策略如下:spring-doc.cadn.net.cn

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

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

AsyncRequestTimeoutExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

ConversionNotSupportedExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

{0} 属性名, {1} 属性值spring-doc.cadn.net.cn

HandlerMethodValidationExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

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

HttpMediaTypeNotAcceptableExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

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

HttpMediaTypeNotAcceptableExceptionspring-doc.cadn.net.cn

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

HttpMediaTypeNotSupportedExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

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

HttpMediaTypeNotSupportedExceptionspring-doc.cadn.net.cn

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

HttpMessageNotReadableExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

HttpMessageNotWritableExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

HttpRequestMethodNotSupportedExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

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

MethodArgumentNotValidExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

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

MissingRequestHeaderExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

{0} 请求头名称spring-doc.cadn.net.cn

MissingServletRequestParameterExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

{0} 请求参数的名称spring-doc.cadn.net.cn

MissingMatrixVariableExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

{0} 矩阵变量名spring-doc.cadn.net.cn

MissingPathVariableExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

{0}路径变量名spring-doc.cadn.net.cn

MissingRequestCookieExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

{0} Cookie名称spring-doc.cadn.net.cn

MissingServletRequestPartExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

{0} 部件名称spring-doc.cadn.net.cn

NoHandlerFoundExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

NoResourceFoundExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

{0} 请求路径(或其中一部分)用于查找资源spring-doc.cadn.net.cn

TypeMismatchExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

{0} 属性名称,{1} 属性值,{2} 所需类型的简单名称spring-doc.cadn.net.cn

UnsatisfiedServletRequestParameterExceptionspring-doc.cadn.net.cn

默认spring-doc.cadn.net.cn

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

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

客户端处理

客户端应用在使用 WebClient 时可以捕获 WebClientResponseException,或在使用 RestTemplate 时捕获 RestClientResponseException,并通过其 getResponseBodyAs 方法将错误响应体解码为任意目标类型,例如 ProblemDetailProblemDetail 的子类。spring-doc.cadn.net.cn