【问题标题】:Spring mvc - error with white space in file name for downloadSpring mvc - 下载文件名中有空格的错误
【发布时间】:2017-07-01 06:48:26
【问题描述】:

我在使用 Spring mvc 下载名称中包含空格的文件时遇到问题。 我要做的是使用 Spring MVC 内置的资源解析器从远程主机下载文件。

我将 Spring 安全性与 Spring MVC 一起使用,但用于测试而不对特定模式应用任何安全性

Spring 安全配置:

    <http>
....
    <intercept-url pattern="/test download/**" access="permitAll" requires-channel="https"  />
...
</http>

然后请求到达配置资源解析器的 MVC 调度程序:

Spring MVC 配置:

<mvc:resources  mapping="/test download/**" location="http://localhost:10089/test/" />

该配置适用于名称中没有空格的文件。在 Spring 模块上启用调试日志我看到两个请求(文件名中有或没有空格)都以相同的方式处理。 下面是解决两个调用时 Spring 调度程序 servlet 的日志。

第一个测试路径:/test download/file.txt

... after security filters ..
DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'mvc-dispatcher' processing GET request for [/portal/test%20download/file.txt]
DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /test download/file.txt
DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Did not find handler method for [/test download/file.txt]
DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /test download/file.txt
DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Did not find handler method for [/test download/file.txt]
DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Matching patterns for request [/test download/file.txt] are [/test download/**]
DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - URI Template variables for request [/test download/file.txt] are {}
DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapping [/test download/file.txt] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[URL [http://localhost:10089/test/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@2a6eb843]]] and 1 interceptor
DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/portal/test%20download/file.txt] is: -1
DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mvc-dispatcher': assuming HandlerAdapter completed request handling
DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request
DEBUG org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

结果:Content of the file is shown in the browser as expected

第二个测试路径:/test download/test file.txt

... after security filters ..
DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'mvc-dispatcher' processing GET request for [/portal/test%20download/test%20file.txt]
DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /test download/test file.txt
DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Did not find handler method for [/test download/test file.txt]
DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Looking up handler method for path /test download/test file.txt
DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Did not find handler method for [/test download/test file.txt]
DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Matching patterns for request [/test download/test file.txt] are [/test download/**]
DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - URI Template variables for request [/test download/test file.txt] are {}
DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapping [/test download/test file.txt] to HandlerExecutionChain with handler [ResourceHttpRequestHandler [locations=[URL [http://localhost:10089/test/]], resolvers=[org.springframework.web.servlet.resource.PathResourceResolver@2a6eb843]]] and 1 interceptor
DEBUG org.springframework.web.servlet.DispatcherServlet - Last-Modified value for [/portal/test%20download/test%20file.txt] is: -1
DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG org.springframework.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'mvc-dispatcher': assuming HandlerAdapter completed request handling
DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request
DEBUG org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

结果:Http 404 is returned

这两个文件在主机的同一个文件夹中,我使用本地服务器测试文件和远程服务器,结果相同。

我试图仅使用 Spring 配置来解决我的需求,因为我需要的基本上类似于代理,但应用了安全规则。

Spring MVC 版本:4.1.6.RELEASE

Spring Security 版本:3.2.5.RELEASE

知道为什么会这样吗?

更新

在 Frederik 提示后,我将用于测试的 tomcat 配置为远程主机来管理 utf-8,我发现当它处理来自 Spring 的请求时,它返回 505。

从浏览器到远程主机的简单调用:

"GET /test/test%20file.txt HTTP/1.1" 200 15

通过 Spring 收到的电话:

“HEAD /test/test file.txt HTTP/1.1”505 -

在配置连接器之前,我确实尝试创建名称中包含 %20 的文件,但它没有工作,所以可能在编码工作之前。

【问题讨论】:

    标签: spring spring-mvc


    【解决方案1】:

    已通过创建自定义资源处理程序解决了该问题。

    我们详细做的是创建一个在启动时作为配置加载的类

    @Configuration
    @EnableWebMvc
    public class WebConfiguration extends WebMvcConfigurerAdapter {
    
    
        /**
         *
         * Add ResourceResolver that fix the whitespace problem in filename url.
         * resources that needs this fix must be configured here instead of inside xml
         *
         * @param registry
         */
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
            registry.addResourceHandler("/test download/**")
                    .addResourceLocations("http://localhost:10089/test/")
                    .resourceChain(true)
                    .addResolver(new CustomPathResourceResolver())
                    ;
        }
    
    
    }
    

    而 CustomPathResourceResolver 是

    import org.springframework.core.io.Resource;
    import org.springframework.web.servlet.resource.PathResourceResolver;
    import org.springframework.web.servlet.resource.ResourceResolver;
    import java.io.IOException;
    
    public class CustomPathResourceResolver extends PathResourceResolver implements ResourceResolver {
    
        @Override
        protected Resource getResource(String resourcePath, Resource location) throws IOException {
            //fixes problems with whitespaces in url
            resourcePath = resourcePath.replace(" ","%20");
            return super.getResource(resourcePath, location);
        }
    }
    

    替换不是最优雅的解决方案 :) 可能,但对于我们的简单需求,现在就足够了。

    【讨论】:

      【解决方案2】:

      负责根据 URL 查找资源的处理程序使用 HandlerMapping .PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE,它对应于您在映射中配置的 /** 值。

      https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java#L407

      我很确定用于获取文件的路径包含转义字符。所以它会寻找一个名为test%20file.txt 的文件。您可以通过在 test download 文件夹中添加一个具有该名称的文件来验证是否是这种情况。

      Spring 实际上会解码 URL - 你能检查一下你的 tomcat/container 是否真的打开了 UTF-8 字符集过滤器吗?

      【讨论】:

      • 如何在浏览器中显示 URL?也许您可以在浏览器中显示之前尝试对 URL 进行编码:java.net.URLEncoder.encode(url,"UTF-8")
      • 这里的问题似乎是从 Spring Security 层解码 URL 后,Resource Handler 没有重新编码。调试默认资源处理程序(在您发布的类中使用)空格不会重新编码。在调试中,我用 %20 覆盖了运行时的值(感谢 eclipse),并且发现文件没有问题。所以我认为目前唯一的解决方案是扩展默认资源处理程序,为解析器添加一个针对特定路径“/test download/**”的“重新编码”步骤。
      猜你喜欢
      • 2015-04-19
      • 1970-01-01
      • 2011-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-07
      • 2015-06-05
      • 1970-01-01
      相关资源
      最近更新 更多