跳到主要内容

错误响应

ChatGPT-4o 中英对照 Error Responses

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 状态。

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

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

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

您可以通过 MVC 配置 使用 WebMvcConfigurer 注册 ErrorResponse 拦截器。使用它来拦截任何 RFC 9457 响应并采取一些措施。

非标准字段

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

一,将未知属性插入到 ProblemDetail 的 "properties" Map 中。当使用 Jackson 库时,Spring Framework 会注册 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 的子类。