最近使用WebMvcConfigurer做请求拦截时,自定义HandlerInterceptor处理用户身份。
但使用WebMvcConfigurer的addInterceptors添加自定义拦截器出现问题,excludePathPatterns一直不生效,导致浏览器无限被拦截器重定向到login,然后继续被拦截。。。重定向。。。拦截。。。
网上大部分是说由于后端重定向到error页面,确实有这种情况,打印拦截器请求的uri就可以发现。
但我不是,由于我配置了context-path,也就是说我的完整请求是{context-path}/**/**这种形式,而且excludePathPatterns也是写的这个完整uri,但是!拦截器的匹配规则是不包含{context-path}的!
举个例子:
你配置了{context-path}为"admin";
你使用WebMvcConfigurer的addInterceptors自定义拦截器,其中不拦截excludePathPatterns配置为"/admin/login";
但spring实际匹配时,实际是用"/login",直接用这个去匹配excludePathPatterns,很明显匹配不到,ok,那就只好进入interceptor;
解决方式:
excludePathPatterns配置时不加{context-path},以上为例,excludePathPatterns应配置为"/login"即可;
为什么Spring不是用完整URI而阉割了{context-path}去做匹配,时间有限暂时未找到原因
具体可以在源码org.springframework.web.servlet.handler.MappedInterceptor的方法org.springframework.web.servlet.handler.MappedInterceptor#matches(javax.servlet.http.HttpServletRequest)查看匹配逻辑
spring-webmvc源码中,org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerExecutionChain方法主要是遍历所有interceptor拦截器,路径如果匹配,就将拦截器添加到执行链HandlerExecutionChain中。
- 其中判断路径匹配,实际是调用org.springframework.web.servlet.handler.MappedInterceptor#matches方法,因为拦截器本身配置了include和exclude方法,exclude匹配上就false,include匹配上就true
- 那么上述匹配路径,用的路径是从哪获取的?是request.getRequestURI()?根据参数名知道是一个lookupPath的字符串,是调用org.springframework.web.util.UrlPathHelper#getLookupPathForRequest得来的
public String getLookupPathForRequest(HttpServletRequest request) { if (this.alwaysUseFullPath) { return this.getPathWithinApplication(request); } else { String rest = this.getPathWithinServletMapping(request); return !"".equals(rest) ? rest : this.getPathWithinApplication(request); } }
- 上面getLookupPathForRequest方法底层不过是一堆查找请求路径、查找上下文路径的字符串操作,不看。关键是在于这个alwaysUseFullPath 布尔属性,它隶属于UrlPathHelper类,具有set方法,目前还不知道哪里可以配置