在用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到以後,可以去試試了。
如果覺得本文對你有幫助的話,可以點個關注,點個贊!感謝