问题
从网页上传70MB大小的CSV失败
报错日志:
org.apache.http.client.ClientProtocolException
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:187)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
......
Caused by: org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:108)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
... 124 more
Caused by: java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
at org.apache.http.impl.io.SessionOutputBufferImpl.streamWrite(SessionOutputBufferImpl.java:124)
......
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
......
原因分析
项目技术:前后端均使用SpringBoot(1.5.22.RELEASE)+Thymeleaf模板引擎搭建。
具体原因:
1、前端模块A 和 后端模块B在application.properties配置文件中存在以下配置
## springboot文件传输大小限制
# maxFileSize 单个数据大小
spring.servlet.multipart.maxFileSize = 500MB
# maxRequestSize 是总数据大小
spring.servlet.multipart.maxRequestSize=500MB
spring.http.multipart.maxFileSize=1024MB
spring.http.multipart.maxRequestSize=1024MB
# tomcat单个文件大小限制
spring.servlet.multipart.max-file-size=1024MB
# tomcat总文件大小限制
spring.servlet.multipart.max-request-size=1024MB
2、A、B模块在各自的SpringApplication启动类中,也存在上传文件大小配置
@SpringBootApplication
@ComponentScan(basePackages={"com.xxx.xxx", "com.xxx.xxx2"})
@ServletComponentScan(basePackages = "com.xxx.xxx")
public class XXXApplication {
public static void main(String[] args) {
SpringApplication.run(XXXApplication.class, args);
}
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
// 允许上传的文件最大值
factory.setMaxFileSize("1024MB"); //KB,MB
// 设置总上传数据总大小
factory.setMaxRequestSize("1024MB");
return factory.createMultipartConfig();
}
}
结论:
Spring Boot 在启动时会先加载 application.properties
或 application.yml
中的配置,然后再加载带有 @Configuration
的配置类(如你的启动类)中的Bean。因此,如果你的 MultipartConfigElement
Bean中的配置与 application.properties
中的配置不一致,那么会以 MultipartConfigElement
Bean中的配置为准。
这是因为Spring Boot的自动配置机制,它会首先加载 application.properties
中的配置,然后在加载Bean时检查这些配置。如果在Bean中找到了与 application.properties
中不一致的配置,那么Spring Boot会使用Bean中的配置覆盖 application.properties
中的配置。
如果你的Spring Boot版本是2.0及以上
然而,你的代码和配置中似乎存在一些混淆。从 Spring Boot 2.0 开始,spring.http.multipart.*
已被 spring.servlet.multipart.*
替代,所以在新版本的Spring Boot应用中,你应该使用后者。因此,如果你的Spring Boot版本是2.0及以上,应该使用以下的配置:
# tomcat单个文件大小限制
spring.servlet.multipart.max-file-size=1024MB
# tomcat总文件大小限制
spring.servlet.multipart.max-request-size=1024MB
然后在你的启动类中创建一个 MultipartConfigElement Bean
:
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
// 单个数据大小
factory.setMaxFileSize("1024MB");
// 总上传数据大小
factory.setMaxRequestSize("1024MB");
return factory.createMultipartConfig();
}
这样,无论你的Spring Boot版本是多少,都可以保证文件上传大小的配置是正确的。
解决方案
1、确认application.properties中的tomcat配置的文件大小
SpringBoot 1.x版本
# tomcat单个文件大小限制
spring.http.multipart.maxFileSize=1024MB
# tomcat总文件大小限制
spring.http.multipart.maxRequestSize=1024MB
或
SpringBoot 2.x版本
# tomcat单个文件大小限制
spring.servlet.multipart.max-file-size=1024MB
# tomcat总文件大小限制
spring.servlet.multipart.max-request-size=1024MB
2、检查Application启动类中或其他配置类位置中的@Bean注解,public MultipartConfigElement multipartConfigElement()配置
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
// 允许上传的文件最大值
factory.setMaxFileSize("1024MB"); //KB,MB
// 设置总上传数据总大小
factory.setMaxRequestSize("1024MB");
return factory.createMultipartConfig();
}
调整为合适的大小即可。
3、如果是从一个前端模块A上传到另一个后端模块B,需要注意A、B模块都需要注意上传文件大小的配置。