将大文件上传到 Apache FileUpload 时忽略 Servlet 响应

Posted

技术标签:

【中文标题】将大文件上传到 Apache FileUpload 时忽略 Servlet 响应【英文标题】:Servlet response ignored when uploading large file to Apache FileUpload 【发布时间】:2022-01-15 20:05:50 【问题描述】:

在使用具有文件大小限制的 Apache FileUpload 和 Tomcat Web 应用程序服务器(版本 9)时,我遇到了奇怪的行为。这是我的代码:

  List<FileItem> multi = null;

  try 
    DiskFileItemFactory factory = new DiskFileItemFactory();
    factory.setRepository(new File(System.getProperty("java.io.tmpdir")));

    ServletFileUpload upload = new ServletFileUpload(factory);
    upload.setFileSizeMax(2 * 1024 * 1024); // 2MB
    upload.setHeaderEncoding("UTF-8");
    multi = upload.parseRequest(request);

    ...
   catch (Exception e) 
    e.printStackTrace();
  

  // send servlet response
  ...

如上所示,文件大小限制为 2MB。

如果我上传一个 1MB 的文件,一切正常,我的 servlet 响应被发送到客户端。

如果我上传一个 3MB 的文件,行为正常:抛出异常并将我的 servlet 响应发送到客户端。

如果我上传 10MB 的文件,行为不正常。抛出异常,但我的 servlet 响应从未发送到客户端。 WireShark 向我展示了 tomcat 以 RST 消息响应,然后客户端尝试一次又一次地发送请求。

经过长时间调试,我可以看到我可以通过将maxSwallowSize 连接器属性(在server.xml 中定义)设置为 -1 或大于 10MB 的值来​​绕过重置代码 (RST)。

如果我删除setFileSizeMax() 电话,一切都会好起来的。

我的问题是:

为什么 3MB 和 10MB 文件的行为不同,因为它们都大于 2BM 限制? 当文件小于/大于限制时maxSwallowSize 的作用是什么

【问题讨论】:

【参考方案1】:

首先,从 Servlet 3.0(Tomcat 7.0)开始,commons-fileupload 的功能被集成到 servlet 容器中:参见HttpServletRequest#getParts。您应该考虑改用此 API。大多数 servlet 容器(包括 Tomcat)在底层使用 commons-fileupload 的重新打包版本。

连接器的maxSwallowSize 属性告诉Tomcat 在Tomcat 重置TCP 套接字之前,HTTP 客户端您已经完成处理请求之后还可以发送多少字节。在您的情况下,这意味着浏览器可以发送超过 2 MiB 限制的字节数。

这是一项安全措施:HTTP 协议本身确实允许服务器在接收完整请求之前发送错误响应(请参阅this question),但有些浏览器不符合这一点(在您的情况下,您不会发送错误状态)。尝试添加:

catch (SizeException e) 
    response.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);

到您的 catch 子句。如果您的浏览器及时响应错误状态码,它将在达到maxSwallowSize 限制之前停止上传,客户端将显示413 错误页面。

【讨论】:

非常感谢您的回答。这证实了我的猜想。我已经尝试发送 413 状态而不进行任何更改。正如***.com/a/18370751/1585114 中提到的那样,客户端(chrome 和 firefox)似乎忽略了这个状态并继续发送数据。

以上是关于将大文件上传到 Apache FileUpload 时忽略 Servlet 响应的主要内容,如果未能解决你的问题,请参考以下文章

java文件上传-使用apache-fileupload组件

Apache Commons fileUpload实现文件上传之一

Apache FileUpload文件上传组件API解析

文件上传fileupload文件接收

解决SpringBoot文件上传报错:org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException

Spring MVC - AngularJS - 文件上传 - org.apache.commons.fileupload.FileUploadException