Exceptions
@Controller
和 @ControllerAdvice 类可以具有 @ExceptionHandler
方法来处理控制器方法的异常,如下例所示:
@Controller
and @ControllerAdvice classes can have
@ExceptionHandler
methods to handle exceptions from controller methods, as the following example shows:
include-code::./SimpleController[indent=0]
Exception Mapping
该异常可能与正在传播的顶级异常(例如直接抛出 IOException
异常)相匹配,也可能与包装器异常(例如在 IllegalStateException
中包装 IOException
异常)内的嵌套原因相匹配。从 5.3 开始,这可以在任意原因级别处相匹配,而以前仅考虑直接原因。
The exception may match against a top-level exception being propagated (e.g. a direct
IOException
being thrown) or against a nested cause within a wrapper exception (e.g.
an IOException
wrapped inside an IllegalStateException
). As of 5.3, this can match
at arbitrary cause levels, whereas previously only an immediate cause was considered.
对于匹配异常类型,最好将目标异常声明为方法参数,如前一个示例所示。当多个异常方法相匹配时,通常会优先考虑根异常匹配,而不是原因异常匹配。更具体地说,ExceptionDepthComparator
用于根据从抛出异常类型开始的深度对异常进行排序。
For matching exception types, preferably declare the target exception as a method argument,
as the preceding example shows. When multiple exception methods match, a root exception match is
generally preferred to a cause exception match. More specifically, the ExceptionDepthComparator
is used to sort exceptions based on their depth from the thrown exception type.
或者,注释声明可以缩小要匹配的异常类型范围,如下面的示例所示:
Alternatively, the annotation declaration may narrow the exception types to match, as the following example shows:
-
Java
-
Kotlin
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handleIoException(IOException ex) {
return ResponseEntity.internalServerError().body(ex.getMessage());
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handleIoException(ex: IOException): ResponseEntity<String> {
return ResponseEntity.internalServerError().body(ex.message)
}
甚至可以使用特定异常类型的列表与非常通用的参数签名结合使用,如下面的示例所示:
You can even use a list of specific exception types with a very generic argument signature, as the following example shows:
-
Java
-
Kotlin
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handleExceptions(Exception ex) {
return ResponseEntity.internalServerError().body(ex.getMessage());
}
@ExceptionHandler(FileSystemException::class, RemoteException::class)
fun handleExceptions(ex: Exception): ResponseEntity<String> {
return ResponseEntity.internalServerError().body(ex.message)
}
根异常匹配和原因异常匹配之间的差异可能会令人惊讶。 The distinction between root and cause exception matching can be surprising. 在前面显示的 In the 在 The behavior is even simpler in the |
我们通常建议您在参数签名中尽可能具体,以减少根异常类型和原因异常类型之间的不匹配可能性。考虑将多匹配方法分解为各个 @ExceptionHandler
方法,每个方法都通过其签名匹配单个特定异常类型。
We generally recommend that you be as specific as possible in the argument signature,
reducing the potential for mismatches between root and cause exception types.
Consider breaking a multi-matching method into individual @ExceptionHandler
methods, each matching a single specific exception type through its signature.
在多个 @ControllerAdvice
排列中,我们建议您在具有对应顺序的 @ControllerAdvice
上声明您的主要根异常映射。虽然根异常匹配优先于原因匹配,但这是在给定控制器或 @ControllerAdvice
类的所有方法之间进行的定义。这意味着优先级较高的 @ControllerAdvice
Bean 上的原因匹配优先于优先级较低 @ControllerAdvice
Bean 上的任何匹配(例如,根匹配)。
In a multi-@ControllerAdvice
arrangement, we recommend declaring your primary root exception
mappings on a @ControllerAdvice
prioritized with a corresponding order. While a root
exception match is preferred to a cause, this is defined among the methods of a given
controller or @ControllerAdvice
class. This means a cause match on a higher-priority
@ControllerAdvice
bean is preferred to any match (for example, root) on a lower-priority
@ControllerAdvice
bean.
最后但并非最不重要的是,@ExceptionHandler
方法实现可以选择通过以原始形式重新抛出给定异常实例来退出处理该异常实例。这对于以下情况非常有用:您仅对根级别匹配或特定上下文中(该上下文无法静态确定)的匹配感兴趣。重新抛出的异常通过剩余的解析链传播,就好像给定的 @ExceptionHandler
方法从一开始就没有匹配一样。
Last but not least, an @ExceptionHandler
method implementation can choose to back
out of dealing with a given exception instance by rethrowing it in its original form.
This is useful in scenarios where you are interested only in root-level matches or in
matches within a specific context that cannot be statically determined. A rethrown
exception is propagated through the remaining resolution chain, as though
the given @ExceptionHandler
method would not have matched in the first place.
Spring MVC 对 @ExceptionHandler
方法的支持建立在 DispatcherServlet
级别的 HandlerExceptionResolver 机制上。
Support for @ExceptionHandler
methods in Spring MVC is built on the DispatcherServlet
level, HandlerExceptionResolver mechanism.
Media Type Mapping
除了异常类型之外,@ExceptionHandler
方法还可以声明可生产的媒体类型。这允许根据 HTTP 客户端请求的媒体类型(通常在“Accept”HTTP 请求头中)来优化错误响应。
In addition to exception types, @ExceptionHandler
methods can also declare producible media types.
This allows to refine error responses depending on the media types requested by HTTP clients, typically in the "Accept" HTTP request header.
应用程序可以直接在注释中为同一异常类型声明可生产的媒体类型:
Applications can declare producible media types directly on annotations, for the same exception type:
/// The provided media type to update the metadata of./// /// /// The operation to be performed./// /// /// The of the fields to update./// /// /// A cancellation token to observe./// /// /// The updated ./// /// /// is null ./// /// /// is null ./// /// /// is not one of the allowed values./// /// /// An error occurred while making the API request./// /// /// An error occurred while making the gRPC request./// [Google.Api.HttpBody(Body = "*" hljs" data-lang="csharp/// /// Updates metadata of a media type./// /// /// The provided media type to update the metadata of./// /// /// The operation to be performed./// /// /// The of the fields to update./// /// /// A cancellation token to observe./// /// /// The updated ./// /// /// is null ./// /// /// is null ./// /// /// is not one of the allowed values./// /// /// An error occurred while making the API request./// /// /// An error occurred while making the gRPC request./// [Google.Api.HttpBody(Body = "*"">[.iokays-original-c6d3a9f857f3eddc1c64ecf5071ad688]
include-code::./MediaTypeController[tag=mediatype,indent=0]
[.iokays-translated-2c8c5ea6035234bd42c2fb63c640f06b]
在此处,方法处理相同的异常类型,但不会因重复而被拒绝。相反,请求“application/json”的 API 客户端将接收一个 JSON 错误,而浏览器会获取一个 HTML 错误视图。每个 `@ExceptionHandler` 注释可以声明多种可生产的媒体类型,错误处理阶段的内容协商将决定使用哪种内容类型。
[.iokays-original-2c8c5ea6035234bd42c2fb63c640f06b]
Here, methods handle the same exception type but will not be rejected as duplicates.
Instead, API clients requesting "application/json" will receive a JSON error, and browsers will get an HTML error view.
Each `@ExceptionHandler` annotation can declare several producible media types,
the content negotiation during the error handling phase will decide which content type will be used.
[id="mvc-ann-exceptionhandler-args"]
== Method Arguments
[role="small"][.small]xref:web/webflux/controller/ann-exceptions.adoc#webflux-ann-exceptionhandler-args[See equivalent in the Reactive stack]
[.iokays-translated-135e6335171b413ab983ca2c3223f8df]
`@ExceptionHandler` 方法支持以下参数:
[.iokays-original-135e6335171b413ab983ca2c3223f8df]
`@ExceptionHandler` methods support the following arguments:
[cols="1,2"]
|===
| Method argument | Description
| Exception type | For access to the raised exception.
| `HandlerMethod` | For access to the controller method that raised the exception.
| `WebRequest`, `NativeWebRequest` | Generic access to request parameters and request and session attributes without direct
use of the Servlet API.
| `jakarta.servlet.ServletRequest`, `jakarta.servlet.ServletResponse` | Choose any specific request or response type (for example, `ServletRequest` or
`HttpServletRequest` or Spring’s `MultipartRequest` or `MultipartHttpServletRequest`).
| `jakarta.servlet.http.HttpSession` | Enforces the presence of a session. As a consequence, such an argument is never `null`.
Note that session access is not thread-safe. Consider setting the
`RequestMappingHandlerAdapter` instance’s `synchronizeOnSession` flag to `true` if multiple
requests are allowed to access a session concurrently.
| `java.security.Principal` | Currently authenticated user — possibly a specific `Principal` implementation class if known.
| `HttpMethod` | The HTTP method of the request.
| `java.util.Locale` | The current request locale, determined by the most specific `LocaleResolver` available — in
effect, the configured `LocaleResolver` or `LocaleContextResolver`.
| `java.util.TimeZone`, `java.time.ZoneId` | The time zone associated with the current request, as determined by a `LocaleContextResolver`.
| `java.io.OutputStream`, `java.io.Writer` | For access to the raw response body, as exposed by the Servlet API.
| `java.util.Map`, `org.springframework.ui.Model`, `org.springframework.ui.ModelMap` | For access to the model for an error response. Always empty.
| `RedirectAttributes` | Specify attributes to use in case of a redirect — (that is to be appended to the query
string) and flash attributes to be stored temporarily until the request after the redirect.
See xref:web/webmvc/mvc-controller/ann-methods/redirecting-passing-data.adoc[Redirect Attributes] and xref:web/webmvc/mvc-controller/ann-methods/flash-attributes.adoc[Flash Attributes].
| `@SessionAttribute` | For access to any session attribute, in contrast to model attributes stored in the
session as a result of a class-level `@SessionAttributes` declaration.
See xref:web/webmvc/mvc-controller/ann-methods/sessionattribute.adoc[`@SessionAttribute`] for more details.
| `@RequestAttribute` | For access to request attributes. See xref:web/webmvc/mvc-controller/ann-methods/requestattrib.adoc[`@RequestAttribute`] for more details.
|===
[id="mvc-ann-exceptionhandler-return-values"]
== Return Values
[role="small"][.small]xref:web/webflux/controller/ann-exceptions.adoc#webflux-ann-exceptionhandler-return-values[See equivalent in the Reactive stack]
[.iokays-translated-04a5d0a421e304a3a2e76e71de7b9622]
`@ExceptionHandler` 方法支持以下返回值:
[.iokays-original-04a5d0a421e304a3a2e76e71de7b9622]
`@ExceptionHandler` methods support the following return values:
[cols="1,2"]
|===
| Return value | Description
| `@ResponseBody` | The return value is converted through `HttpMessageConverter` instances and written to the
response. See xref:web/webmvc/mvc-controller/ann-methods/responsebody.adoc[`@ResponseBody`].
| `HttpEntity<B>`, `ResponseEntity<B>` | The return value specifies that the full response (including the HTTP headers and the body)
be converted through `HttpMessageConverter` instances and written to the response.
See xref:web/webmvc/mvc-controller/ann-methods/responseentity.adoc[ResponseEntity].
| `ErrorResponse` | To render an RFC 9457 error response with details in the body,
see xref:web/webmvc/mvc-ann-rest-exceptions.adoc[Error Responses]
| `ProblemDetail` | To render an RFC 9457 error response with details in the body,
see xref:web/webmvc/mvc-ann-rest-exceptions.adoc[Error Responses]
| `String` | A view name to be resolved with `ViewResolver` implementations and used together with the
implicit model — determined through command objects and `@ModelAttribute` methods.
The handler method can also programmatically enrich the model by declaring a `Model`
argument (described earlier).
| `View` | A `View` instance to use for rendering together with the implicit model — determined
through command objects and `@ModelAttribute` methods. The handler method may also
programmatically enrich the model by declaring a `Model` argument (descried earlier).
| `java.util.Map`, `org.springframework.ui.Model` | Attributes to be added to the implicit model with the view name implicitly determined
through a `RequestToViewNameTranslator`.
| `@ModelAttribute` | An attribute to be added to the model with the view name implicitly determined through
a `RequestToViewNameTranslator`.
Note that `@ModelAttribute` is optional. See "`Any other return value`" at the end of
this table.
| `ModelAndView` object | The view and model attributes to use and, optionally, a response status.
| `void` | A method with a `void` return type (or `null` return value) is considered to have fully
handled the response if it also has a `ServletResponse` an `OutputStream` argument, or
a `@ResponseStatus` annotation. The same is also true if the controller has made a positive
`ETag` or `lastModified` timestamp check (see xref:web/webmvc/mvc-caching.adoc#mvc-caching-etag-lastmodified[Controllers] for details).
If none of the above is true, a `void` return type can also indicate "`no response body`" for
REST controllers or default view name selection for HTML controllers.
| Any other return value | If a return value is not matched to any of the above and is not a simple type (as determined by
{spring-framework-api}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty]),
by default, it is treated as a model attribute to be added to the model. If it is a simple type,
it remains unresolved.
|===