在用SpringBoot搭建的服务时,如果你用到了文件上传类型的接口的话,可能会遇到今天说的这个坑:
之前部署到服务器上的SpringBoot应用一直工作得好好的,而且上传文件的接口之前也一直好好的,都没问题;
但是有一天突然发现调用上传文件的接口失败,出现了类似以下的提示
The temporary upload location [/tmp/tomcat.4232587034585098924.8083/work/Tomcat/localhost/ROOT] is not valid
具体如下:
java.io.IOException: The temporary upload location [/tmp/tomcat.4232587034585098924.8083/work/Tomcat/localhost/ROOT] is not valid
at org.apache.catalina.connector.Request.parseParts(Request.java:2843)
at org.apache.catalina.connector.Request.parseParameters(Request.java:3216)
at org.apache.catalina.connector.Request.getParameter(Request.java:1137)
at org.apache.catalina.connector.RequestFacade.getParameter(RequestFacade.java:381)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:75)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
一、问题分析
从打印的异常信息来看,问题比较清晰,这个目录is not valid,就是非法无效的意思
根据异常信息里的文件路径,试着去查看下这个目录,结果发现,没有这个目录(小朋友你是否有很多问号?)
哈哈哈。
带着众多的问号,接着分析:这个目录到底是干啥用的?为什么需要这个目录?
先简单描述一下原因:因为SpringBoot上传的文件时,会缓存到本地磁盘,而缓存的路径就是上面说的那个路径
接着引入的疑问就是:为什么要缓存到本地的临时文件?
因为流读取一次消费之后,后面无法再从流中获取数据,所以缓存到临时目录里,方便后续复用,这个感兴趣的话,可以打断点跟一下Spring的源码。
那又有一个问题,之前上传接口能用,也就是说之前这个临时目录是有的,那为什么现在这个临时目录忽然不在了?
Springboot项目启动时会创建一个/tmp/tomcat.xxxx.xxx/work/Tomcat/localhost/ROOT的临时目录,作为文件上传的临时目录
但是该目录会在n天之后被系统自动清理掉,这个清理是由linux操作系统完成的
知道了这些后,那咱们的问题怎么解决呢?
二、解决方案
方法1、重启应用
因为这个临时目录是在Springboot项目启动时创建的,所以,再重启一下服务就会再次重新创建一个目录
但是这个方法治标不治本,所以不推荐
方法2、增加服务配置,自定义baseDir
在Springboot配置文件里自定义一个不会被定时删除的文件目录,这样就不会被定时的删除了
server.tomcat.basedir=/tmp/tomcat
方法3、注入bean,手动配置临时目录
@Bean
MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
factory.setLocation("/tmp/tomcat");
return factory.createMultipartConfig();
}
这个和方法2差不多,都是自定义一个目录,不被删除
方法4、配置不删除tmp目录下的缓存目录
vim /usr/lib/tmpfiles.d/tmp.conf
# 最后添加一行
x /tmp/tomcat.*
比较推荐最后一种方法,比较简单通用
好了,以上就是这个问题的解决办法了,get到以后,可以去试试了。
如果觉得本文对你有帮助的话,可以点个关注,点个赞!感谢