SpringBoot下自定义拦截器preHandle方法执行多次原因分析

问题描述:在SpringBoot中自定义拦截器Interceptor时,发现当preHandler返回值为true时,有些请求的preHandler方法被执行两次。后来通过在代码中输出请求路径找到了原因。拦截器实现、拦截器注册以及处理器的代码如下:

//通过实现HandlerInterceptor接口实现拦截,这个类需要注册
public class InterceptorByInterface implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("此路是我开,此树是我栽,要想从此过,留下买路财");
        //输出请求路径
        System.out.println(request.getRequestURI());
        //true表示请求放行,false表示拦截请求,不再向下寻找处理器
        return true;
    }
}
//注册拦截器的配置类
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        //  /**表示拦截所有请求
        String[] addPath = {"/**"};
        // 放行getStudent和getUser两个请求:其中getUser请求没有对应的处理器
        String[] excludePath = {"/getStudent","/getUser"};
        registry.addInterceptor(new InterceptorByInterface()).addPathPatterns(addPath).excludePathPatterns(excludePath);
    }
}
//本例中只有StudentController一个处理器,并且只能处理getStudent这一个请求
@Controller
public class StudentController {

    @Autowired
    private StudentService studentService;

    @RequestMapping(value = "/getStudent")
    @ResponseBody
    public Object getStudent() {
		
		//getStudentById是去数据库中查询,对应的方法实现就不贴上来了
        Student student = studentService.getStudentById(4);

        return student;
        }
    }

我一共测试了三个请求路径:
1./getStudent:被放行并且有对应处理器。这类请求不会在后台输出拦截器中的语句。
2./getUser:被放行但没有对应处理器。这类请求执行一次拦截器的内容
3./wrongPage:被拦截也没有对应处理器。这类请求执行两次拦截器的内容
SpringBoot下自定义拦截器preHandle方法执行多次原因分析
为了弄清楚后两种情况产生的原因,在自定义的拦截器中加了对请求路径的输出,即输出request.getRequestURI()。第二种请求路径下,浏览器最终响应的页面是404,是这样的,一眼望去仿佛和正常的404不太一样呢,然而我并没有深入思考这个问题。而是转向了后台
![在这里插入图片描述5932734.png)SpringBoot下自定义拦截器preHandle方法执行多次原因分析
后台的输出是这样的:
SpringBoot下自定义拦截器preHandle方法执行多次原因分析
输出了语句,说明拦截器中preHandle被执行了一次,但是请求路径是error,而不是浏览器发出的getUser。这说明getUser请求被拦截器放行之后,去找能够处理自己的处理器,但是没有找到,于是发出了一个error的请求,这个请求又被拦截器拦截了(代码中只放行了getStudent和getUser两个请求),所以输出了拦截语句。后来通过查看源码,发现error请求的配置类是ErrorMvcAutoConfiguration,具体执行在BasicErrorController中,返回了一个404页面。(关于具体处理流程,可参考https://blog.csdn.net/zhengzhaoyang122/article/details/84451647)这个404是SpringBoot中默认的,而不是浏览器中自带的这种:
SpringBoot下自定义拦截器preHandle方法执行多次原因分析
后来又测试了第三种请求路径(没有被放行也没有处理器的请求),浏览器和后台的响应分别为
SpringBoot下自定义拦截器preHandle方法执行多次原因分析
SpringBoot下自定义拦截器preHandle方法执行多次原因分析
wrongPage请求被拦截执行一次,但因为preHandle返回true,它就去向下执行,去找对应的处理器,没有找到,又发出error请求,又被拦截一次。这也向我们展示了拦截器和处理器执行的顺序,是拦截器preHandle方法在前,处理器在后的,preHandle方法执行时并不知道现在的整个请求有没有对应的处理器