解決SpringBoot文件上傳異常提示The temporary upload location xxx is not valid

在用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到以後,可以去試試了。

如果覺得本文對你有幫助的話,可以點個關注,點個贊!感謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章