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

一、前言

  在前面使用《自定义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异常为什么不会被全局异常处理器处理了。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姠惢荇者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值