Error Responses

REST 服务的一个常见要求是在错误响应的主体中包含详细信息。Spring 框架支持“用于 HTTP API 的问题详情”规范,https://datatracker.ietf.org/doc/html/rfc9457[RFC 9457]。

A common requirement for REST services is to include details in the body of error responses. The Spring Framework supports the "Problem Details for HTTP APIs" specification, RFC 9457.

以下是此支持的主要抽象:

The following are the main abstractions for this support:

  • ProblemDetail — representation for an RFC 9457 problem detail; a simple container for both standard fields defined in the spec, and for non-standard ones.

  • ErrorResponse — contract to expose HTTP error response details including HTTP status, response headers, and a body in the format of RFC 9457; this allows exceptions to encapsulate and expose the details of how they map to an HTTP response. All Spring MVC exceptions implement this.

  • ErrorResponseException — basic ErrorResponse implementation that others can use as a convenient base class.

  • ResponseEntityExceptionHandler — convenient base class for an @ControllerAdvice that handles all Spring MVC exceptions, and any ErrorResponseException, and renders an error response with a body.

Render

可以从任何 @ExceptionHandler@RequestMapping 方法返回 ProblemDetailErrorResponse 来呈现 RFC 9457 响应。该处理过程如下:

You can return ProblemDetail or ErrorResponse from any @ExceptionHandler or from any @RequestMapping method to render an RFC 9457 response. This is processed as follows:

  • The status property of ProblemDetail determines the HTTP status.

  • The instance property of ProblemDetail is set from the current URL path, if not already set.

  • For content negotiation, the Jackson HttpMessageConverter prefers "application/problem+json" over "application/json" when rendering a ProblemDetail, and also falls back on it if no compatible media type is found.

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

To enable RFC 9457 responses for Spring WebFlux exceptions and for any ErrorResponseException, extend ResponseEntityExceptionHandler and declare it as an @ControllerAdvice in Spring configuration. The handler has an @ExceptionHandler method that handles any ErrorResponse exception, which includes all built-in web exceptions. You can add more exception handling methods, and use a protected method to map any exception to a ProblemDetail.

您可以通过 MVC Config 使用 WebMvcConfigurer 注册 ErrorResponse 拦截器。使用它来拦截任何 RFC 7807 响应并采取一些操作。

You can register ErrorResponse interceptors through the MVC Config with a WebMvcConfigurer. Use that to intercept any RFC 7807 response and take some action.

Non-Standard Fields

可以通过两种方法扩展超出 RFC 9457 响应的非标准字段。

You can extend an RFC 9457 response with non-standard fields in one of two ways.

方法一,插入到 ProblemDetail 的“属性”Map 中。在使用 Jackson 库时,Spring Framework 会注册 ProblemDetailJacksonMixin,以确保此“属性”Map 被解包并呈现为响应中的顶级 JSON 属性,同样,在反序列化期间的任何未知属性也被插入到此 Map 中。

One, insert into the "properties" Map of ProblemDetail. When using the Jackson library, the Spring Framework registers ProblemDetailJacksonMixin that ensures this "properties" Map is unwrapped and rendered as top level JSON properties in the response, and likewise any unknown property during deserialization is inserted into this Map.

你也可以扩展 ProblemDetail 以添加非标准的专用属性。ProblemDetail 中的拷贝构造函数允许子类轻松从现有的 ProblemDetail 创建。它可以集中管理,比如在 @ControllerAdvice 中,比如 ResponseEntityExceptionHandler 从一个 ProblemDetail 的异常重新创建一个子类,子类具有附加的非标准的字段。

You can also extend ProblemDetail to add dedicated non-standard properties. The copy constructor in ProblemDetail allows a subclass to make it easy to be created from an existing ProblemDetail. This could be done centrally, e.g. from an @ControllerAdvice such as ResponseEntityExceptionHandler that re-creates the ProblemDetail of an exception into a subclass with the additional non-standard fields.

Customization and i18n

一种常见的需求是自定义和国际化错误的响应详情。对于 Spring MVC 的异常自定义问题详情也是一种良好的实践,可以避免泄露实现详情。本部分介绍对其的支持。

It is a common requirement to customize and internationalize error response details. It is also good practice to customize the problem details for Spring MVC exceptions to avoid revealing implementation details. This section describes the support for that.

ErrorResponse 公开消息代码以用于“类型”、“标题”和“详情”,以及用于“详情”字段的消息代码参数。ResponseEntityExceptionHandler 通过 MessageSource 确定这些,并相应地更新对应的 ProblemDetail 字段。

An ErrorResponse exposes message codes for "type", "title", and "detail", as well as message code arguments for the "detail" field. ResponseEntityExceptionHandler resolves these through a MessageSource and updates the corresponding ProblemDetail fields accordingly.

消息代码的默认策略如下:

The default strategy for message codes is as follows:

  • "type": problemDetail.type.[fully qualified exception class name]

  • "title": problemDetail.title.[fully qualified exception class name]

  • "detail": problemDetail.[fully qualified exception class name][suffix]

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

An ErrorResponse may expose more than one message code, typically adding a suffix to the default message code. The table below lists message codes, and arguments for Spring MVC exceptions:

Exception Message Code Message Code Arguments

AsyncRequestTimeoutException

(default)

ConversionNotSupportedException

(default)

{0} property name, {1} property value

HandlerMethodValidationException

(default)

{0} list all validation errors. Message codes and arguments for each error are also resolved via MessageSource.

HttpMediaTypeNotAcceptableException

(default)

{0} list of supported media types

HttpMediaTypeNotAcceptableException

(default) + ".parseError"

HttpMediaTypeNotSupportedException

(default)

{0} the media type that is not supported, {1} list of supported media types

HttpMediaTypeNotSupportedException

(default) + ".parseError"

HttpMessageNotReadableException

(default)

HttpMessageNotWritableException

(default)

HttpRequestMethodNotSupportedException

(default)

{0} the current HTTP method, {1} the list of supported HTTP methods

MethodArgumentNotValidException

(default)

{0} the list of global errors, {1} the list of field errors. Message codes and arguments for each error are also resolved via MessageSource.

MissingRequestHeaderException

(default)

{0} the header name

MissingServletRequestParameterException

(default)

{0} the request parameter name

MissingMatrixVariableException

(default)

{0} the matrix variable name

MissingPathVariableException

(default)

{0} the path variable name

MissingRequestCookieException

(default)

{0} the cookie name

MissingServletRequestPartException

(default)

{0} the part name

NoHandlerFoundException

(default)

NoResourceFoundException

(default)

TypeMismatchException

(default)

{0} property name, {1} property value

UnsatisfiedServletRequestParameterException

(default)

{0} the list of parameter conditions

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

Unlike other exceptions, the message arguments for MethodArgumentValidException and HandlerMethodValidationException are based on a list of MessageSourceResolvable errors that can also be customized through a MessageSource resource bundle. See Customizing Validation Errors for more details.

Client Handling

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

A client application can catch WebClientResponseException, when using the WebClient, or RestClientResponseException when using the RestTemplate, and use their getResponseBodyAs methods to decode the error response body to any target type such as ProblemDetail, or a subclass of ProblemDetail.