对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

异常

如果在请求映射期间发生异常,或从请求处理程序(例如 @Controller)抛出异常,DispatcherServlet 会委托给一个 HandlerExceptionResolver bean 链来解析该异常并提供替代处理方式,通常是返回一个错误响应。spring-doc.cadn.net.cn

下表列出了可用的 HandlerExceptionResolver 实现:spring-doc.cadn.net.cn

表1. HandlerExceptionResolver 实现类
HandlerExceptionResolver <description> </description>

SimpleMappingExceptionResolverspring-doc.cadn.net.cn

异常类名与错误视图名称之间的映射。适用于在浏览器应用程序中渲染错误页面。spring-doc.cadn.net.cn

DefaultHandlerExceptionResolverspring-doc.cadn.net.cn

解析由 Spring MVC 抛出的异常,并将其映射到 HTTP 状态码。 另请参阅替代方案 ResponseEntityExceptionHandler错误响应spring-doc.cadn.net.cn

ResponseStatusExceptionResolverspring-doc.cadn.net.cn

通过 @ResponseStatus 注解解析异常,并根据注解中的值将其映射到相应的 HTTP 状态码。spring-doc.cadn.net.cn

ExceptionHandlerExceptionResolverspring-doc.cadn.net.cn

通过调用 @ExceptionHandler@Controller 类中的 @ControllerAdvice 方法来解析异常。参见@ExceptionHandler 方法spring-doc.cadn.net.cn

解析器链

你可以通过在 Spring 配置中声明多个 HandlerExceptionResolver bean 并根据需要设置它们的 order 属性来形成一个异常解析器链。 2 属性值越高,该异常解析器在链中的位置就越靠后。spring-doc.cadn.net.cn

HandlerExceptionResolver 的契约规定它可以返回:spring-doc.cadn.net.cn

  • 一个指向错误视图的 ModelAndViewspring-doc.cadn.net.cn

  • 如果异常已在解析器内部处理,则返回一个空的 ModelAndViewspring-doc.cadn.net.cn

  • null 表示该异常尚未被解决,以便后续的解析器尝试处理;如果到最后异常仍未被解决,则允许其向上传播至 Servlet 容器。spring-doc.cadn.net.cn

MVC 配置会自动声明内置的解析器,用于处理默认的 Spring MVC 异常、带有 @ResponseStatus 注解的异常,以及支持 @ExceptionHandler 方法。您可以自定义该列表或将其替换。spring-doc.cadn.net.cn

容器错误页面

如果异常未被任何 HandlerExceptionResolver 解决,从而继续向上抛出,或者响应状态被设置为错误状态(即 4xx、5xx), Servlet 容器可以渲染一个默认的 HTML 错误页面。要自定义容器的默认错误页面, 可以在 web.xml 中声明一个错误页面映射。 以下示例展示了如何实现这一点:spring-doc.cadn.net.cn

<error-page>
	<location>/error</location>
</error-page>

根据前面的示例,当异常向上抛出或响应具有错误状态时, Servlet 容器会在容器内部向配置的 URL(例如 /error)发起一次 ERROR 类型的转发(dispatch)。随后,该请求由 DispatcherServlet 进行处理,可能会将其映射到某个 @Controller,该控制器可以实现为返回一个带有模型的错误视图名称,或者渲染一个 JSON 响应,如下例所示:spring-doc.cadn.net.cn

@RestController
public class ErrorController {

	@RequestMapping(path = "/error")
	public Map<String, Object> handle(HttpServletRequest request) {
		Map<String, Object> map = new HashMap<>();
		map.put("status", request.getAttribute("jakarta.servlet.error.status_code"));
		map.put("reason", request.getAttribute("jakarta.servlet.error.message"));
		return map;
	}
}
@RestController
class ErrorController {

	@RequestMapping(path = ["/error"])
	fun handle(request: HttpServletRequest): Map<String, Any> {
		val map = HashMap<String, Any>()
		map["status"] = request.getAttribute("jakarta.servlet.error.status_code")
		map["reason"] = request.getAttribute("jakarta.servlet.error.message")
		return map
	}
}
Servlet API 并未提供通过 Java 代码创建错误页面映射的方式。不过,您可以同时使用 WebApplicationInitializer 和一个极简的 web.xml