2

我们使用Zuul将请求转发给内部微服务。内部服务有2个端点(一个PUT端点和一个POST端点)。我们发现多部分请求在到达我们内部的PUT端点之前已经损坏。带多部分的PUT请求被Zuul/DispatcherServlet破坏(多部分数据被删除)

多部分数据似乎从请求中删除。这似乎只是PUT请求的情况,因为POST完美工作。

如果我们用cURL直接命中内部PUT端点,则请求处理正确。相应的卷曲命令和请求体看起来像这样:

curl -v -X PUT -H "Content-Type: multipart/form-data" -F "[email protected]/path/to/file.txt" "http://localhost:8081/file/put" 

接头:

{用户代理= [卷曲/ 7.35.0],主机= [本地主机:8082],接受= [/],content-length = [203],expect = [100-continue],content-type = [multipart/form-data;边界= ------------------------ c1efb86a9054e387]}

实体:

----------- --------------- c1efb86a9054e387 Content-Disposition:form-data; NAME = “文件”;文件名= “helloworld.txt” 的Content-Type:text/plain的

这是我的文件内容

----------------------- --- c1efb86a9054e387--

然而,如果我们试图通过Zuul卷曲打PUT端点,请求如下:

curl -X PUT -H "Content-Type: multipart/form-data" -F "[email protected]/path/to/file.txt" "http://localhost:8082/file/put" 

页眉:

{user-agent = [curl/7.35.0],accept = [/],expect = [100-continue],content-type = [multipart/form-data; boundary = hkBnDNXOcDTwkuL1qLhglF6i4NA2YREd],x-forwarding-host = [localhost:8081],x-forwarded-proto = [http],x-forwarded-prefix = [/ file],x -forwarded-port = [8081],x-forwarded-for = [127.0.0.1],接受编码= [gzip的],内容长度= [38],主= [本地主机:8082],连接= [保持活动]}

实体:

--hkBnDNXOcDTwkuL1qLhglF6i4NA2YREd--

请注意,实体不完整。

我已将示例代码上传到此存储库:https://github.com/trcodestore/zuul-put-demo。该存储库包含2个用于演示此问题的小型项目。自述文件包含构建和运行说明。

我知道请求最初由Spring的DispatcherServlet处理,然后最终由ZuulServlet处理。我相信这是造成问题的DispatcherServlet。我们可以通过在“/ zuul”前加上所有的请求URI来绕过DispatcherServlet--这允许多部分请求直接进入ZuulServlet,然后按预期工作。但是,这不是一个理想的解决方案。

任何意见,将不胜感激。谢谢。

回答

3

好的,我有解决方案(credit: Mohammad Zolmajd)。

Spring Boot使用StandardServletMultipartResolver来处理多部分 - 它假定所有的多部分请求将与POST一起提交。

要允许StandardServletMultipartResolver处理PUT请求,我们必须重写isMultiPart方法。我结束了使用以下配置:

@Bean 
public MultipartResolver multipartResolver() { 
    return new StandardServletMultipartResolver() { 
    @Override 
    public boolean isMultipart(HttpServletRequest request) { 
     String method = request.getMethod().toLowerCase(); 
     if (!Arrays.asList("put", "post").contains(method)) { 
      return false; 
     } 
     String contentType = request.getContentType(); 
     return (contentType != null &&contentType.toLowerCase().startsWith("multipart/")); 
    } 
    }; 
}