您的位置 首页 java

spring boot 虚拟路径url中文无法访问

原因:

从2.6.0开始 Spring MVC 处理程序映射匹配请求路径的默认策略已从 AntPathMatcher 更改为PathPatternParser。

基本可以确定是这个更改导致的,不知道是不是bug,更改之后具体的不知道改动了哪些,能力有限,暂时未知

springboot一般配置资源是这样:

 @Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public  void  addResourceHandlers(ResourceHandler registry  registry) { registry.addResourceHandler("/files/**").addResourceLocations(" File :E:/FileUpload/HmiInterface/";
    }
}  

一点分析:

从addResourceHandlers追踪,最终发现会到ResourceHttp request Handler,通过ResourceHttpRequestHandler调试发现,在使用PathPatternParser 后,现在传进来的url是原始的未 decode 过的url,但是UrlPathHelper 默认设置是 Decode URL的,这就导致重复进行了一次encode———-ResourceHttpRequestHandler.java————-

 @Nullable
protected Resource getResource(HttpServletRequest request) throws IO Exception  {
//这里获取的path是原始的encode的URL,而小于2.6版本会根据UrlPathHelper 里设置的decodeurl会有不同的值
String path = (String)request.getAttribute(HandlerMapping.PATH_ WITHIN _HANDLER_MAPPING_ATTRIBUTE);
 if  (path == null) {
throw new Illegal State Exception("Required request attribute '" + HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE + "' is not set");
} else {
path = this.processPath(path);
if ( String Utils.hasText(path) && !this.isInvalidPath(path)) {
if (this.isInvalidEncodedPath(path)) {
return null;
} else {
Assert.notNull(this.resolverChain, "ResourceResolverChain not initialized.");
Assert.notNull(this.transformerChain, " Resource TransformerChain not initialized.");
//这里调用到PathResourceResolver
Resource resource = this.resolverChain.resolveResource(request, path, this.getLocations());
if (resource != null) {
resource = this.transformerChain.transform(request, resource);
}
return resource;
}
} else {
return null;
}
}
}  

———–PathResourceResolver.java—————– private String encodeOrDecodeIfNecessary(String path, @Nullable HttpServletRequest request, Resource location) {

if (this.shouldDecodeRelativePath(location, request)) {

return Uri Utils.decode(path, Standard charset s.UTF_8);

} else if (this.shouldEncodeRelativePath(location) && request != null) {//因为UrlPathHelper 默认是decodeURL的,理论上这里的path应该是decode过的,所以这里会进行encode一次,便于查找文件时decode回来,但是现在这里的path都是encode过的,并不是原始的url,不论你UrlPathHelper 设置decode还是关闭,这就导致后面查文件的时候decode回来的是encode的url,所以找不到文件

  Charset  charset = (Charset)this.locationCharsets.getOrDefault(location, StandardCharsets.UTF_8);
             StringBuilder  sb = new StringBuilder();
             StringTokenizer  tokenizer = new StringTokenizer(path, "/");

            while(tokenizer.hasMoreTokens()) {
                String value = UriUtils.encode(tokenizer.nextToken(), charset);
                sb.append(value);
                sb.append('/');
            }

            if (!path.endsWith("/")) {
                sb.setLength(sb.length() - 1);
            }

            return sb.toString();
        } else {
            return path;
        }
    }
private boolean shouldEncodeRelativePath(Resource location) {
        return location  instanceof  UrlResource && this.urlPathHelper != null && this.urlPathHelper.isUrlDecode();
    }  

这就导致在 Abstract FileResolvingResource.java getFile的时候获取不到文件了

 public File getFile() throws IOException {
        URL url = this.getURL();
        return url.get Protocol ().startsWith("vfs") ? AbstractFileResolvingResource.VfsResourceDelegate.getResource(url).getFile() : ResourceUtils.getFile(url, this.getDescription());
    }  

因为这里ResourceUtils去获取文件时解码出来的是我们请求的原始的encodeurl,还需要在decode一次才是真正的文件名,所以我们可以关闭decode,但是这样会影响到哪些地方 未知解决办法:

1.UrlPathHelper 设置不decodeurl

 @Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper=new UrlPathHelper();
        urlPathHelper.setUrlDecode(false);
        urlPathHelper.setDefaultEncoding(StandardCharsets.UTF_8.name());
        configurer.setUrlPathHelper(urlPathHelper);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {  registry.addResourceHandler("/files/**").addResourceLocations("file:E:/FileUpload/HmiInterface/");
    }
}  

2.使用原来的AntPathMatcher (推荐)

 spring.mvc.pathmatch.matching-strategy=ant-path-matcher  

能力有限,往上不是很好去调试了,不知道这算不算是bug吧,等待后续观察。

文章来源:智云一二三科技

文章标题:spring boot 虚拟路径url中文无法访问

文章地址:https://www.zhihuclub.com/170011.shtml

关于作者: 智云科技

热门文章

网站地图