带有多部分的 PUT 请求被 Zuul / DispatcherServlet 损坏(多部分数据被删除)
PUT requests with multipart are corrupted by Zuul / DispatcherServlet (the multipart data is removed)
我们正在使用 Zuul 将请求转发到内部微服务。内部服务有 2 个端点(一个 PUT 端点和一个 POST 端点)。我们发现多部分请求在到达我们的内部 PUT 端点之前已损坏。
多部分数据似乎已从请求中删除。这似乎只是 PUT 请求的情况,因为 POST 工作得很好。
如果我们直接使用 cURL 访问内部 PUT 端点,请求将得到正确处理。相应的 cURL 命令和请求正文如下所示:
curl -v -X PUT -H "Content-Type: multipart/form-data" -F "file=@/path/to/file.txt" "http://localhost:8081/file/put"
Headers:
{user-agent=[curl/7.35.0], host=[localhost:8082], accept=[/], content-length=[203], expect=[100-continue], content-type=[multipart/form-data; boundary=------------------------c1efb86a9054e387]}
Entity:
--------------------------c1efb86a9054e387 Content-Disposition: form-data; name="file"; filename="helloworld.txt" Content-Type: text/plain
this is my file content
--------------------------c1efb86a9054e387--
但是,如果我们尝试通过 Zuul 使用 cURL 访问 PUT 端点,则请求如下所示:
curl -X PUT -H "Content-Type: multipart/form-data" -F "file=@/path/to/file.txt" "http://localhost:8082/file/put"
Header:
{user-agent=[curl/7.35.0], accept=[/], expect=[100-continue], content-type=[multipart/form-data;boundary=hkBnDNXOcDTwkuL1qLhglF6i4NA2YREd], x-forwarded-host=[localhost:8081], x-forwarded-proto=[http], x-forwarded-prefix=[/file], x-forwarded-port=[8081], x-forwarded-for=[127.0.0.1], accept-encoding=[gzip], content-length=[38], host=[localhost:8082], connection=[Keep-Alive]}
Entity:
--hkBnDNXOcDTwkuL1qLhglF6i4NA2YREd--
请注意实体不完整。
我已将示例代码上传到此存储库:https://github.com/trcodestore/zuul-put-demo。存储库包含 2 个用于演示此问题的小项目。自述文件包含构建和 运行 说明。
我知道请求最初由 Spring 的 DispatcherServlet 处理,然后最终由 ZuulServlet 处理。我相信是 DispatcherServlet 导致了这个问题。我们可以通过在所有请求 URI 前加上“/zuul”前缀来绕过 DispatcherServlet——这允许多部分请求直接转到 ZuulServlet,然后它按预期工作。然而,这不是一个理想的修复。
如有任何建议,我们将不胜感激。谢谢。
好的,我有解决方案 (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/"));
}
};
}
我们正在使用 Zuul 将请求转发到内部微服务。内部服务有 2 个端点(一个 PUT 端点和一个 POST 端点)。我们发现多部分请求在到达我们的内部 PUT 端点之前已损坏。
多部分数据似乎已从请求中删除。这似乎只是 PUT 请求的情况,因为 POST 工作得很好。
如果我们直接使用 cURL 访问内部 PUT 端点,请求将得到正确处理。相应的 cURL 命令和请求正文如下所示:
curl -v -X PUT -H "Content-Type: multipart/form-data" -F "file=@/path/to/file.txt" "http://localhost:8081/file/put"
Headers:
{user-agent=[curl/7.35.0], host=[localhost:8082], accept=[/], content-length=[203], expect=[100-continue], content-type=[multipart/form-data; boundary=------------------------c1efb86a9054e387]}
Entity:
--------------------------c1efb86a9054e387 Content-Disposition: form-data; name="file"; filename="helloworld.txt" Content-Type: text/plain
this is my file content
--------------------------c1efb86a9054e387--
但是,如果我们尝试通过 Zuul 使用 cURL 访问 PUT 端点,则请求如下所示:
curl -X PUT -H "Content-Type: multipart/form-data" -F "file=@/path/to/file.txt" "http://localhost:8082/file/put"
Header:
{user-agent=[curl/7.35.0], accept=[/], expect=[100-continue], content-type=[multipart/form-data;boundary=hkBnDNXOcDTwkuL1qLhglF6i4NA2YREd], x-forwarded-host=[localhost:8081], x-forwarded-proto=[http], x-forwarded-prefix=[/file], x-forwarded-port=[8081], x-forwarded-for=[127.0.0.1], accept-encoding=[gzip], content-length=[38], host=[localhost:8082], connection=[Keep-Alive]}
Entity:
--hkBnDNXOcDTwkuL1qLhglF6i4NA2YREd--
请注意实体不完整。
我已将示例代码上传到此存储库:https://github.com/trcodestore/zuul-put-demo。存储库包含 2 个用于演示此问题的小项目。自述文件包含构建和 运行 说明。
我知道请求最初由 Spring 的 DispatcherServlet 处理,然后最终由 ZuulServlet 处理。我相信是 DispatcherServlet 导致了这个问题。我们可以通过在所有请求 URI 前加上“/zuul”前缀来绕过 DispatcherServlet——这允许多部分请求直接转到 ZuulServlet,然后它按预期工作。然而,这不是一个理想的修复。
如有任何建议,我们将不胜感激。谢谢。
好的,我有解决方案 (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/"));
}
};
}