最近项目框架升级,发现原本支持url带有%20这种编码后的空格,升级后却报404。

例如:有个Controller处理路径为/hello/world的请求。

升级前(spring core 4.2.3.RELEASE)://hello/world/%20/hello/world都能正常返回。

升级后(spring core 5.3.23)://hello/world正常返回,但是/%20/hello/world却报404

我们知道Spring MVC是通过url查找匹配的handler来处理请求的。

通过DispatcherServlet#doDispatch方法层层跟进,我们能定位到org.springframework.util.AntPathMatcher是最终确定路径是否能匹配的地方。

那么,想要找出问题的原因所在,我们只需要对比升级前和升级后的版本AntPathMatcher有什么区别即可。

1
2
3
4
// spring core 4.2.3.RELEASE
// pattern为controller的路径,path为url中的路径
String[] pattDirs = tokenizePattern(pattern); // /hello/world => [hello, world]
String[] pathDirs = tokenizePath(path); // /%20/hello/world => [hello, world]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// spring core 5.3.23
String[] pattDirs = tokenizePattern(pattern);
// 这是新版特有的代码,就是这里直接返回false。
// 这里涉及到trimTokens变量,如果trimTokens为true,相同参数的情况下,升级前后的匹配结果就一致了
// 而且刚好5.3.23默认为false,4.2.3默认为true
if (fullMatch && this.caseSensitive && !isPotentialMatch(path, pattDirs)) {
  return false;
}

String[] pathDirs = tokenizePath(path);

所以,只需要将doDispatch时使用的AntPathMatcher的trimTokens设置为true即可。

那么问题来了,怎么设置呢?

一种方法是,在代码里一层层找能设置AntPathMatcher的扩展点。另一种当然就是直接搜索引擎搜了。

然后我就搜到了这个,正好与我的需求相反。Disable trimming of whitespace from path variables in Spring 3.2

解决方法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
  
  @Override
    protected void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.setPathMatcher(antPathMatcher());
    }

    @Bean
    public AntPathMatcher antPathMatcher() {
        final AntPathMatcher antPathMatcher = new AntPathMatcher();
        antPathMatcher.setTrimTokens(true); //此为重点
        return antPathMatcher;
    }
}