<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[Heck's  Blog]]></title> 
<link>https://www.heckjj.com/index.php</link> 
<description><![CDATA[一瞬间的决定，往往可以改变很多，事实上，让自己成功的往往不是知识，是精神！ 如果你总是为自己找借口，那只好让成功推迟。执行力，今天！]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[Heck's  Blog]]></copyright>
<item>
<link>https://www.heckjj.com/post//</link>
<title><![CDATA[上传找不到临时目录, 出现500错误，nested exception is java.lang. RuntimeException: java.nio.file. NoSuchFileException: /tmp/undertow]]></title> 
<author>Heck &lt;@hecks.tk&gt;</author>
<category><![CDATA[Web开发]]></category>
<pubDate>Mon, 17 Jul 2023 11:53:35 +0000</pubDate> 
<guid>https://www.heckjj.com/post//</guid> 
<description>
<![CDATA[ 
	 Linux 系统中，Spring Boot 应用以 java -jar 命令启动时，会在操作系统的 /tmp 目录下生成一个 tomcat（或 undertow ）临时目录，上传的文件先要转换成临时文件保存在这个文件夹下面。由于临时 /tmp 目录下的文件，在长时间（10天）没有使用的情况下，系统执行了 tmp 目录清理服务（systemd-tmpfiles-clean.service）,导致 /tmp/undertow...8090 文件被清理，然而在上传的时候，undertow 服务器需要创建/tmp/undertow...8090/undertow...upload 临时文件，但是调用 Files.createFile(...) 的时候就会发现找不到父目录，才导致了以上的错误。<br/><br/>具体错误日志(参考)<br/>undertow<br/><br/>java.nio.file.NoSuchFileException: /tmp/undertow.17753558642503713859.8085/undertow7370242804103803588upload<br/><br/>Tomcat<br/><br/>The temporary upload location [/tmp/tomcat.7957874575370093230.8088/work/Tomcat/localhost/ROOT] is not valid<br/><br/>重现方法<br/>找到类 io.undertow.server.handlers.form.MultiPartParserDefinition<br/>定位到如下代码<br/><br/>@Override<br/>public void beginPart(final HeaderMap headers) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;this.currentFileSize = 0;<br/>&nbsp;&nbsp;&nbsp;&nbsp;this.headers = headers;<br/>&nbsp;&nbsp;&nbsp;&nbsp;final String disposition = headers.getFirst(Headers.CONTENT_DISPOSITION);<br/>&nbsp;&nbsp;&nbsp;&nbsp;if (disposition != null) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (disposition.startsWith(&quot;form-data&quot;)) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;currentName = Headers.extractQuotedValueFromHeader(disposition, &quot;name&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fileName = Headers.extractQuotedValueFromHeaderWithEncoding(disposition, &quot;filename&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (fileName != null &amp;&amp; fileSizeThreshold == 0) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (tempFileLocation != null) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file = Files.createTempFile(tempFileLocation, &quot;undertow&quot;, &quot;upload&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; else &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;file = Files.createTempFile(&quot;undertow&quot;, &quot;upload&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;createdFiles.add(file);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fileChannel = FileChannel.open(file, StandardOpenOption.READ, StandardOpenOption.WRITE);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; catch (IOException e) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new RuntimeException(e);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&#125;<br/><br/>在 createdFiles.add(file); 处打断点，复制file的 path 的值找到该文件并将其删除；放开断点，错误重现；<br/><br/>解决方案<br/>方案1 (推荐)<br/>在 applicaiton.yml(applicaiton.property) 中添加配置 ：spring.servlet.multipart.location<br/>spring.servlet.multipart.location 底层就是 createMultipartConfig 中的 factory.setLocation ，见源码：org.springframework.boot.autoconfigure.web.servlet.MultipartProperties#createMultipartConfig<br/><br/>spring:<br/>&nbsp;&nbsp;servlet:<br/>&nbsp;&nbsp;&nbsp;&nbsp;multipart:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;location: /data/tmp<br/><br/>手动指定目录后，必须保证该目录存在，并由读写的权限<br/>创建该目录 mkdir -p /data/tmp<br/><br/>方法二<br/>使用配置类配置, 类似方案1<br/><br/>@Bean<br/>public MultipartConfigElement multipartConfigElement() &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;MultipartConfigFactory factory = new MultipartConfigFactory();<br/>&nbsp;&nbsp;&nbsp;&nbsp;factory.setLocation(System.getProperty(&quot;/data/tmp&quot;));<br/>&nbsp;&nbsp;&nbsp;&nbsp;return factory.createMultipartConfig();<br/>&#125;<br/><br/>方案三(不推荐)<br/>手动创建临时目录<br/><br/>mkdir -p /tmp/undertow.17753558642503713859.8085/undertow7370242804103803588upload<br/><br/>方案四(不推荐)<br/>修改系统配置，排除该临时目录<br/><br/>vim /usr/lib/tmpfiles.d/tmp.con<br/># 文件最后添加<br/>x /tmp/undertow*
]]>
</description>
</item><item>
<link>https://www.heckjj.com/post//#blogcomment</link>
<title><![CDATA[[评论] 上传找不到临时目录, 出现500错误，nested exception is java.lang. RuntimeException: java.nio.file. NoSuchFileException: /tmp/undertow]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>https://www.heckjj.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>