求助, Java 接口上传 2G 以上大文件 EOFException: null

2022-12-09 11:52:30 +08:00
 shiyu6226

最近在写一个 web 端的私人网盘服务,测试发现上传 2G 以上大文件时 后台会出现异常,请问有大佬做过相关的需求吗?怎么解决这类问题?

异常日志如下

ERROR 19593 --- [io-18073-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.impl.IOFileUploadException: Processing of multipart/form-data request failed. java.io.EOFException] with root cause

java.io.EOFException: null ...

我修改了好多参数也不好使

@Configuration @Slf4j public class EmbeddedTomcatConfig implements WebServerFactoryCustomizer {

@Override
public void customize(ConfigurableServletWebServerFactory factory) {
    log.info("Init EmbeddedTomcatConfig...");
    ((TomcatServletWebServerFactory)factory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
        @Override
        public void customize(Connector connector) {
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            protocol.setMaxConnections(3000);
            protocol.setMaxThreads(800);
            protocol.setAcceptCount(200);
            protocol.setSelectorTimeout(30000);
            protocol.setSessionTimeout(60000 * 2);
            protocol.setConnectionTimeout(60000 * 5);
            protocol.setDisableUploadTimeout(false);
            protocol.setConnectionUploadTimeout(60000 * 10);
        }
    });
}

}

application 参数

spring.servlet.multipart.max-request-size=-1 spring.servlet.multipart.max-file-size=-1 server.tomcat.max-swallow-size=-1 server.tomcat.max-http-form-post-size=-1

控制层

@ResponseBody
@ApiOperation(value = "上传文件",notes = "上传文件")
@RequestMapping(value = "/FilesUpload",method = RequestMethod.POST)
public BaseResponse uploadFiles(
        @RequestParam(required = true) MultipartFile files,
        HttpServletRequest request,
        HttpServletResponse response
) {
    if (files.isEmpty() || files.getSize() == 0) {
        response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
        return BaseResponse.initErrorBaseResponse("不能上传空文件!");
    }
    try {
        return BaseResponse.initSuccessBaseResponse(fileExecuteService.uploadFiles(files,request), "操作成功");
    } catch (Exception e) {
        response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
        return BaseResponse.initErrorBaseResponse(e.getMessage());
    }
}
4062 次点击
所在节点    程序员
30 条回复
DinnyXu
2022-12-09 22:09:45 +08:00
说一个大概的思路,前端检测上传的文件大小,根据文件大小进行压缩分片,比如 1G 的文件,分成 1024 个压缩包,每个压缩包 1M ,然后进行轮询请求上传到 OSS ,将 1024 个文件放到一个文件夹, 获取 OSS 的文件夹路径传给后端,由后端根据此路径读取 OSS 上传的所有分片文件,然后进行异步处理组装。
shiyu6226
2022-12-09 23:29:12 +08:00
@aguesuka
异常不在 service 也不在 controller ,我观察到的情况是 tomcat 缓存目录正在接收大文件时 到 2 个多 G 就中断 出异常了。
堆栈日志其实是打印全的,但是有点多,我就只发了主要的
aguesuka
2022-12-10 00:04:05 +08:00
@guyeu null 就 null 呗, 异常栈都打出来了
aguesuka
2022-12-10 00:14:28 +08:00
@guyeu e.getMessage 改成啥都可以, 重点是要把 error 当第二个参数传进去
aguesuka
2022-12-10 00:55:01 +08:00
spring.servlet.multipart.max-file-size: -1
spring.servlet.multipart.max-request-size: -1
亲测 ok, 依赖只有 spring-boot-starter-web:3.0.0
aguesuka
2022-12-10 02:00:27 +08:00
multipart 文件在转成 MultipartFile 的时候必须读完整个流, 所以会缓存到内存或硬盘里, 估计还有别的配置到上限了.
bertieranO0o
2022-12-10 02:28:45 +08:00
@aguesuka 一般不建议文件大小设置无限大,给个业务范围内的合理上限值即可
bertieranO0o
2022-12-10 02:31:19 +08:00
@DinnyXu 根本不需要这么复杂,就拿你举例的 OSS 来说,记得 19 年的时候 OSS 都已经有很成熟的支持分片上传的 API 了
DinnyXu
2022-12-10 15:28:29 +08:00
@bertieranO0o 你也知道你调用的是 API 哈,我说的是逻辑思维,API 谁不会调
bertieranO0o
2022-12-10 18:18:38 +08:00
@DinnyXu 想听听你的“异步处理组装”的逻辑

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/901299

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX