文章目录
- 基本说明
- 问题描述
- 问题原因
- 解决方法
- 前端执行的所有请求都通过Controller,而不是直接访问html
- 定义一个/error路径的方法
- 总结
基本说明
我的前后端项目是放在一起的,前后端都是由springMVC进行控制,但是现在我在拦截器的preHandle方法中抛出的异常并没有被全局异常处理器捕获到。下面是我的项目结构
问题描述
我定义了一个拦截器,并且将其注入到了spring容器
然后在全局异常处理器中对异常进行了处理
这个时候,如果我没有登录就访问主页面,那么程序并不会执行到handleLoginException方法,而是直接去调寻找/error路径的页面
可以看见,我访问的页面是http://localhost/admin/index.html,当我没有登录的时候应该跳转到登录页面,也就是login.html,但是在拦截器的preHandle抛出异常之后并没有被全局异常处理器捕获,而是再去寻找/error路径的处理器,然后又被拦截->抛出异常->寻找/error处理器->拦截,直接就产生了循环。
问题原因
想要分析这个问题,那么就要去看springMVC源码了。
首先找到org.springframework.web.servlet.DispatcherServlet#doDispatch,这个就是springMVC的核心。在这个方法里面找到执行preHandle的方法
现在已知preHandle中会抛出一个LoginException异常,于是直接看catch中的代码
可以发现会将异常记录,然后执行processDispatchResult方法
继续查看processHandlerException方法
这个方法里面就是遍历所有的异常解析器来解析,首先看看DefaultErrorAttributes的解析器
这里就是简单的记录一下,然后去查看HandlerExceptionResolverComposite
可以发现在在里面又有3个解析器来对异常进行解析,需要关注的就是的一个异常解析器,这个就是处理全局异常的,继续往里面看
可以发现首先会对handler进行检查
可以发现这里会直接返回false,也就是并不会对异常进行处理,然后异常会一直往外面抛,最终执行到org.apache.catalina.core.StandardHostValve#status方法,然后返回一个默认/error路径
这里就有疑问了,为什么在全局异常处理器不会对preHandle抛出的异常进行处理呢?如下
原因就是DispathcerServlet#doDispatch中获取执行链时,发现请求的是一个页面,而不是Controller,于是就导致了执行上面的shouldApplyTo方法时不会进行处理,直接返回false。
解决方法
前端执行的所有请求都通过Controller,而不是直接访问html
定义一个admin/index方法,返回admin/index.html页面
这样在执行getHandler时就可以获取到执行器链
这样在preHandle中抛出的异常就可以被解析
执行异常处理器的方法
可以发现上面的异常就可以被全局异常处理器捕获了
定义一个/error路径的方法
由于默认情况下会打到error,可以将默认返回的页面写到该方法中。
总结
如果前后端项目放在一起写,前端项目的访问也由springMVC来控制,那么当访问前端页面时,如果在拦截器preHandle中抛出异常,这个异常并不会被全局异常处理器所捕获,而是会将该错误一直往上抛,最终由org.apache.catalina.core.StandardHostValve#status方法所处理,会默认去访问htpp://localhost/error接口。
是会将该错误一直往上抛,最终由org.apache.catalina.core.StandardHostValve#status方法所处理,会默认去访问htpp://localhost/error接口。
如果请求的是后端定义的接口,那么在preHandle中抛出的异常会被全局异常处理器捕获