SpringBoot异常处理 之 404异常为什么不会被全局异常处理器处理呢(默认情况下)?

导读:本篇文章讲解 SpringBoot异常处理 之 404异常为什么不会被全局异常处理器处理呢(默认情况下)?,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

一、前言

  在前面使用《自定义HandlerExceptionResolver类处理异常》和 《@ControllerAdvice+@ExceptionHandler注解实现异常处理》两篇内容中,我们如果没有经过特殊配置,会发现404异常,不会被被全局异常处理器进行处理,为什么呢?404异常和其他异常又有什么区别呢?带着这个疑问,我们开始今天的学习。

二、如何让404异常在全局异常处理器中生效?

  其实,让404异常可以被全局异常处理器捕获非常容易,只需要在application.properties配置文件中添加如下配置即可:

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

  其中,throw-exception-if-no-handler-found表示当没有对应处理器时,允许抛出异常;而add-mappings表示是否为静态资源添加对应的处理器。其实,默认404异常不被全局处理器拦截,也就是因为这两个原因造成的,我们下面将具体分析,这两个原因是如何让404异常不被全局异常处理器捕获的。

三、add-mappings属性

3.1、初始化

  根据该属性的值,在初始化的过程中,会决定是否在容器中添加静态资源处理器。初始化过程如下:

  首先,在WebMvcConfigurationSupport类的resourceHandlerMapping()方法中进行资源处理器的初始化,其中又通过addResourceHandlers()方法完成资源处理器的添加,具体实现如下:

@Bean
@Nullable
public HandlerMapping resourceHandlerMapping(
		@Qualifier("mvcUrlPathHelper") UrlPathHelper urlPathHelper,
		@Qualifier("mvcPathMatcher") PathMatcher pathMatcher,
		@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
		@Qualifier("mvcConversionService") FormattingConversionService conversionService,
		@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {

	Assert.state(this.applicationContext != null, "No ApplicationContext set");
	Assert.state(this.servletContext != null, "No ServletContext set");

	ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
			this.servletContext, contentNegotiationManager, urlPathHelper);
	addResourceHandlers(registry);

	AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
	if (handlerMapping == null) {
		return null;
	}
	handlerMapping.setPathMatcher(pathMatcher);
	handlerMapping.setUrlPathHelper(urlPathHelper);
	handlerMapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
	handlerMapping.setCorsConfigurations(getCorsConfigurations());
	return handlerMapping;
}

  然后,在上述方法中调用addResourceHandlers()时,又经过一系列的调用最终调用了WebMvcAutoConfiguration类中的addResourceHandlers()方法,这里会初始化一个可以匹配“/**”的映射处理器,如下所示:
在这里插入图片描述
  然后再回到WebMvcConfigurationSupport类的resourceHandlerMapping()方法时,可以发现,实际上就是添加了一个SimpleUrlHandlerMapping实例,其中可以处理“/**”请求。

在这里插入图片描述
  至此,关于根据add-mappings属性加载处理静态资源的处理器就初始化完成了。

3.2、如何让全局处理不生效呢?

  404异常其中一个不生效的原因,就是因为这个静态资源处理器的原因,我们还是从doDispatch()方法开始分析,其中通过getHandler(processedRequest);获取对应处理器时,如果没有获取到就会通过调用noHandlerFound()方法抛出NoHandlerFoundException异常,但是我们跟踪代码会发现,默认我们这里可以获取到一个处理器实例,即ResourceHttpRequestHandler实例,所以就不会再抛出NoHandlerFoundException异常,所以该404异常也就不会再被全局处理捕获了。
在这里插入图片描述

  当继续执行时,这个时候根据该请求地址去获取静态资源。当然是没有的,这个时候就会为响应对象response设置一个错误状态,如下图所示:

在这里插入图片描述
  再然后,就会重新再触发一个新的request请求,而且请求地址默认为“/error”,这个里就对应到了SpringBoot默认的异常处理机制中了,详情可以参考《SpringBoot默认的处理异常机制,默认错误页面是怎么产生的呢?》

  至此,关于add-mappings属性影响404异常被捕获的详细内容我们就分析清楚了,下面我们继续分析throw-exception-if-no-handler-found为什么会影响404异常被捕获呢?

四、throw-exception-if-no-handler-found配置

  该配置属性的影响就更加的简单了,主要是在noHandlerFound()方法中使用,这里就是根据这个属性来判断是抛出NoHandlerFoundException异常,还是在response响应对象中设置错误状态,具体实现如下:

protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
	if (pageNotFoundLogger.isWarnEnabled()) {
		pageNotFoundLogger.warn("No mapping for " + request.getMethod() + " " + getRequestUri(request));
	}
	if (this.throwExceptionIfNoHandlerFound) {
		throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
				new ServletServerHttpRequest(request).getHeaders());
	}
	else {
		response.sendError(HttpServletResponse.SC_NOT_FOUND);
	}
}

  至此,我们就清楚了404异常为什么不会被全局异常处理器处理了。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/68728.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!