SpringMVC 拦截器失效

结论

如果你的工程配置了 Context-Path:

server:
  port: 8080
  servlet:
    context-path: /admin

那么在拦截器路径配置处,就不需要写 Context-Path 的路径:

registry.addInterceptor(jwtAuthenticationInterceptor())
        .addPathPatterns("/**")
        .excludePathPatterns("/login");

这样代表着需要拦截器拦截这样的路径:/admin/**

错误示例:

registry.addInterceptor(jwtAuthenticationInterceptor())
        .addPathPatterns("/admin/**")
        .excludePathPatterns("/admin/login");

这样代表着需要拦截器拦截这样的路径:/admin/admin/**

原因

SpringMVC 会将请求路径剔除 Context-Path 后在匹配 Controller 与拦截器。

栗子:

  1. Context-Path:/admin
  2. 拦截器的拦截路径:/admin/**
  3. 请求路径:/admin/user/page

请求路径剔除 Context-Path:/user/page,匹配拦截器路径:/admin/** 匹配失败,故拦截器不会执行。

具体源代码如何处理的,可以查看 org.springframework.web.servlet.handler.MappedInterceptor的 matches 方法:

public boolean matches(HttpServletRequest request) {
	Object path = ServletRequestPathUtils.getCachedPath(request);
	if (this.pathMatcher != defaultPathMatcher) {
		path = path.toString();
	}
	boolean isPathContainer = (path instanceof PathContainer);
	if (!ObjectUtils.isEmpty(this.excludePatterns)) {
		for (PatternAdapter adapter : this.excludePatterns) {
			if (adapter.match(path, isPathContainer, this.pathMatcher)) {
				return false;
			}
		}
	}
	if (ObjectUtils.isEmpty(this.includePatterns)) {
		return true;
	}
	// 注意此时的 Path 已经被剔除了,剔除过程可以追踪一下前面的方法调用栈。
	// includePatterns 就是拦截器中配置的拦截路径
	for (PatternAdapter adapter : this.includePatterns) {
		if (adapter.match(path, isPathContainer, this.pathMatcher)) {
			return true;
		}
	}
	return false;
}

版权声明:本文为qq_38074398原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。