Apache commons fileupload 仅在 Firefox 中超时

Apache commons fileupload timeout only with Firefox

我在我的 java 项目中使用 Apache commons fileupload 1.4 库。 我有一个 html 部分,其中包含一个带有文件输入和一些隐藏字段的经典表单。

我在使用 Firefox >= 52 上传大约 >500ko 的文件时遇到问题

在 Chrome 或 Internet Explorer 中处理 10mo 的文件效果很好。 但是使用 Firefox,我在提交表单后等待几分钟后超时。

经过一些调试,我看到导致超时的代码是:

List<FileItem> items = (new ServletFileUpload(new DiskFileItemFactory())).parseRequest(request);

引起等待的部分是"parseRequest"。

我尝试在 IntelliJ 中使用调试器调试请求的内容,但无法以原始格式复制此请求的整个内容值 object。

它在这些情况下有效: - Firefox : version <= 52 or file size < 500ko (around, it's not really precise) - IE浏览器 - Chrome

没有文件大小限制,好像要看请求大小,因为解析请求部分太花时间了...

我在两种情况下收到带有 Firefox 扩展的 HTTP 请求。 一个生成上传 3mo 的文件不起作用(请求文件很大,是上传文件大小的 3 倍): https://code.empreintesduweb.com/13561.html

一个生成的上传文件 200ko 有效(请求文件很小): https://code.empreintesduweb.com/13560.html

其实主要区别是在Chrome或IE中,我在请求中没有上传文件的原始内容 headers :

部分: 对象 溪流 .... 尾流 内对象

仅在 Firefox 中显示...

这里有一些值得尝试的东西:

如果您提供更多信息,例如 apache / java / servlet 的版本,以及更多代码(尤其是 request 的定义),我们也可能会更好地帮助您

Some ressources that could be helpful:
XMLHttpRequest
Sending_files_using_a_FormData_object
How to set a header for a HTTP GET request, and trigger file download?

您可以尝试设置最大文件大小,可能文件大小超过了最大阈值。根据documentation

  • Uploaded items should be retained in memory as long as they are reasonably small.
  • Larger items should be written to a temporary file on disk.
  • Very large upload requests should not be permitted.
  • The built-in defaults for the maximum size of an item to be retained in memory, the maximum permitted size of an upload request, and the location of temporary files are acceptable.

尝试以下操作:

 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            // Set factory constraints
           DiskFileItemFactory factory = new DiskFileItemFactory();
           factory.setSizeThreshold(yourMaxMemorySize);
           ServletContext servletContext = this.getServletConfig().getServletContext();
           File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
           factory.setRepository(repository);
            List<FileItem> items = new ServletFileUpload(factory).parseRequest(request);
            for (FileItem item : items) {
                if (item.isFormField()) {
                    // Process regular form field (input type="text|radio|checkbox|etc", select, etc).
                    String fieldName = item.getFieldName();
                    String fieldValue = item.getString();
                    // ... (do your job here)
                } else {
                    // Process form file field (input type="file").
                    String fieldName = item.getFieldName();
                    String fileName = FilenameUtils.getName(item.getName());
                    InputStream fileContent = item.getInputStream();
                    // ... (do your job here)
                }
            }
        } catch (FileUploadException e) {
            throw new ServletException("Cannot parse multipart request.", e);
        }

        // ...
    }

在这里,我们为文件提供了一个临时位置,因为文件很大。

尝试使用 setMaxInactiveInterval 方法设置会话超时

 request.getSession().setMaxInactiveInterval(1200);

parameter Specifies the time, in seconds, between client requests before the servlet container will invalidate this session. An interval value of zero or less indicates that thesession should never timeout.

感谢您的所有回答。 最后,我成功解决了这个问题,但实际上……并不是。 我注意到我的表格中有一些特定的东西。 我有两个输入,一个是标准文件输入,另一个是在任何上传之前接收由一些奇怪的 js 以 base64 编码的文件内容。 所以我有一次文件的原始内容,还有 base64 格式的文件。为什么 ?!我不知道。

但是我删除了所有这些,我使用标准输入文件创建了一个新的简单干净的表单。 我使用来自 ServletFileUpload 的流 API,它可以工作,而且对于大文件只需要几秒钟。

所以我不是很明白(例如为什么问题只出现在某些浏览器上),但我找到了解决方案 ;)

谢谢!