Spring Boot應(yīng)用上傳文件時(shí)報(bào)錯(cuò)的原因及解決方案
問(wèn)題描述
Spring Boot應(yīng)用(使用默認(rèn)的嵌入式Tomcat)在上傳文件時(shí),偶爾會(huì)出現(xiàn)上傳失敗的情況,后臺(tái)報(bào)錯(cuò)日志信息如下:“The temporary upload location is not valid”。
原因追蹤
這個(gè)問(wèn)題的根本原因是Tomcat的文件上傳機(jī)制引起的!
Tomcat在處理文件上傳時(shí),會(huì)將客戶端上傳的文件寫入臨時(shí)目錄,這個(gè)臨時(shí)目錄默認(rèn)在/tmp路徑下,如:“/tmp/tomcat.6574404581312272268.18333/work/Tomcat/localhost/ROOT”。
而操作系統(tǒng)對(duì)于/tmp目錄會(huì)不定時(shí)進(jìn)行清理,如果正好因?yàn)椴僮飨到y(tǒng)的清理導(dǎo)致對(duì)應(yīng)的臨時(shí)目錄被刪除,客戶端再上傳文件時(shí)就會(huì)報(bào)錯(cuò):“The temporary upload location is not valid”。
實(shí)際上,追蹤一下源碼會(huì)發(fā)現(xiàn),如果不明確設(shè)置Tomcat的文件上傳臨時(shí)目錄,默認(rèn)讀取的是Servlet上下文對(duì)象的屬性“javax.servlet.context.tempdir”值,如下源碼:
- org.apache.catalina.connector.Request
private void parseParts(boolean explicit) {
//...
MultipartConfigElement mce = this.getWrapper().getMultipartConfigElement();
//...
// 讀取MultipartConfigElement對(duì)象的location屬性
String locationStr = mce.getLocation();
File location;
if (locationStr != null && locationStr.length() != 0) {
location = new File(locationStr);
if (!location.isAbsolute()) {
location = (new File((File)context.getServletContext().getAttribute("javax.servlet.context.tempdir"), locationStr)).getAbsoluteFile();
}
} else {
// 如果location屬性值為空,則讀取Servlet上下文對(duì)象的屬性“javax.servlet.context.tempdir”值(如:/tmp/tomcat.6574404581312272268.18333/work/Tomcat/localhost/ROOT)
location = (File)context.getServletContext().getAttribute("javax.servlet.context.tempdir");
}
//...
}
解決辦法
既然是因?yàn)樯蟼魑募呐R時(shí)路徑被刪除導(dǎo)致的問(wèn)題,就要確保改臨時(shí)目錄不會(huì)被刪除。
2種解決方法:
(1)通過(guò)Spring Boot的配置參數(shù)“spring.servlet.multipart.location”明確指定上傳文件的臨時(shí)目錄,確保該路徑已經(jīng)存在,而且該目錄不會(huì)被操作系統(tǒng)清除。
spring.servlet.multipart.location=/data/tmp
如上所示,將上傳文件的臨時(shí)目錄指定到路徑“/data/tmp”下。
實(shí)際上,在Spring Boot中關(guān)于上傳文件的所有配置參數(shù)如下所示:
# MULTIPART (MultipartProperties) spring.servlet.multipart.enabled=true # Whether to enable support of multipart uploads. spring.servlet.multipart.file-size-threshold=0B # Threshold after which files are written to disk. spring.servlet.multipart.location= # Intermediate location of uploaded files. spring.servlet.multipart.max-file-size=1MB # Max file size. spring.servlet.multipart.max-request-size=10MB # Max request size. spring.servlet.multipart.resolve-lazily=false # Whether to resolve the multipart request lazily at the time of file or parameter access.
(2)在Spring容器中明確注冊(cè)MultipartConfigElement對(duì)象,通過(guò)MultipartConfigFactory指定一個(gè)路徑。
在上述源碼追蹤中就發(fā)現(xiàn),Tomcat會(huì)使用MultipartConfigElement對(duì)象的location屬性作為上傳文件的臨時(shí)目錄。
/**
* 配置上傳文件臨時(shí)目錄
* @return
*/
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
// tmp.dir參數(shù)在啟動(dòng)腳本中設(shè)置
String path = System.getProperty("tmp.dir");
if(path == null || "".equals(path.trim())) {
path = System.getProperty("user.dir");
}
String location = path + "/tmp";
File tmpFile = new File(location);
// 如果臨時(shí)目錄不存在則創(chuàng)建
if (!tmpFile.exists()) {
tmpFile.mkdirs();
}
// 明確指定上傳文件的臨時(shí)目錄
factory.setLocation(location);
return factory.createMultipartConfig();
}
參考
以上就是Spring Boot應(yīng)用上傳文件時(shí)報(bào)錯(cuò)的原因及解決方案的詳細(xì)內(nèi)容,更多關(guān)于Spring Boot應(yīng)用上傳文件時(shí)報(bào)錯(cuò)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
手?jǐn)]一個(gè)Spring?Boot?Starter并上傳到Maven中央倉(cāng)庫(kù)
本文主要介紹了手?jǐn)]一個(gè)Spring?Boot?Starter并上傳到Maven中央倉(cāng)庫(kù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
Springsecurity Oauth2如何設(shè)置token的過(guò)期時(shí)間
如果用戶在指定的時(shí)間內(nèi)有操作就給token延長(zhǎng)有限期,否則到期后自動(dòng)過(guò)期,如何設(shè)置token的過(guò)期時(shí)間,本文就來(lái)詳細(xì)的介紹一下2021-08-08
Java堆&優(yōu)先級(jí)隊(duì)列示例講解(下)
這篇文章主要通過(guò)示例詳細(xì)為大家介紹Java中的堆以及優(yōu)先級(jí)隊(duì)列,文中的示例代碼講解詳細(xì),對(duì)我們了解java有一定幫助,需要的可以參考一下2022-03-03
Spring Cloud如何切換Ribbon負(fù)載均衡模式
這篇文章主要介紹了Spring Cloud如何切換Ribbon負(fù)載均衡模式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
JAVA時(shí)間戳-Calendar類使用(包括set,get,add方法)
這篇文章主要介紹了JAVA時(shí)間戳-Calendar類使用(包括set,get,add方法),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
SpringData Repository Bean方法定義規(guī)范代碼實(shí)例
這篇文章主要介紹了SpringData Repository Bean方法定義規(guī)范代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08

