Spring Boot集成Undertow生产环境文件上传报NoSuchFileException求助
Undertow + Spring Boot 文件上传仅生产环境报错 NoSuchFileException
刚接触Undertow,在Spring Boot应用中实现文件上传功能时,本地及预发环境(均为Linux服务器)运行正常,但仅生产环境出现报错。预发环境的/tmp目录下能看到Undertow生成的临时文件夹,但生产环境部署后/tmp目录为空,且两台服务器文件权限一致。
上传代码
public static String uploadFile(MultipartFile multipartFile, Long partnerId) throws Exception { if (multipartFile == null || multipartFile.isEmpty()) return null; File file = new File(System.getProperty("java.io.tmpdir") + "/" + UUID.randomUUID() + "." + FilenameUtils.getExtension(multipartFile.getOriginalFilename())); multipartFile.transferTo(file); System.out.println("File Path "+file.getAbsolutePath()); return uploadFile(file, partnerId); }
报错堆栈
Java.lang.RuntimeException: java.nio.file.NoSuchFileException: /tmp/undertow.3862881763240028662.4010/undertow3870310975240593973upload at io.undertow.server.handlers.form.MultiPartParserDefinition$MultiPartUploadHandler.beginPart(MultiPartParserDefinition.java:261) at io.undertow.util.MultipartParser$ParseState.headerName(MultipartParser.java:208) at io.undertow.util.MultipartParser$ParseState.parse(MultipartParser.java:123) at io.undertow.server.handlers.form.MultiPartParserDefinition$MultiPartUploadHandler.parseBlocking(MultiPartParserDefinition.java:232) at io.undertow.servlet.spec.HttpServletRequestImpl.parseFormData(HttpServletRequestImpl.java:835) at io.undertow.servlet.spec.HttpServletRequestImpl.getParameter(HttpServletRequestImpl.java:714) at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:85) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:114) at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:104) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68) at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132) at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.servlet.handlers.SessionRestoringHandler.handleRequest(SessionRestoringHandler.java:119) at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269) at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78) at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133) at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130) at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249) at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78) at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99) at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376) at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:750) Caused by: java.nio.file.NoSuchFileException: /tmp/undertow.3862881763240028662.4010/undertow3870310975240593973upload at sun.nio.fs.UnixException.translateToIOException(UnixException.java:86) at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102) at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107) at sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:214) at java.nio.file.Files.newByteChannel(Files.java:361) at java.nio.file.Files.createFile(Files.java:632) at java.nio.file.TempFileHelper.create(TempFileHelper.java:138) at java.nio.file.TempFileHelper.createTempFile(TempFileHelper.java:161) at java.nio.file.Files.createTempFile(Files.java:852) at io.undertow.server.handlers.form.MultiPartParserDefinition$MultiPartUploadHandler.beginPart(MultiPartParserDefinition.java:254)
可能的解决方案
1. 检查生产环境/tmp的临时文件清理机制
生产环境通常会配置tmpwatch或类似工具自动清理/tmp下的过期文件,Undertow的临时文件夹可能在创建后被立即删除。可以:
- 查看生产环境的
tmpwatch配置,排除Undertow相关的临时目录 - 手动指定Undertow的上传临时目录,避免使用系统默认的
/tmp
2. 手动配置Undertow的临时上传目录
在Spring Boot配置文件中指定Undertow的临时目录:
# application.properties server.undertow.servlet.multipart.save-dir=/opt/app/temp/undertow-uploads
或者YAML格式:
# application.yml server: undertow: servlet: multipart: save-dir: /opt/app/temp/undertow-uploads
确保该目录存在且应用进程有读写权限。
3. 调整代码中的临时文件路径
避免使用系统默认的/tmp,改用自定义的非临时目录:
public static String uploadFile(MultipartFile multipartFile, Long partnerId) throws Exception { if (multipartFile == null || multipartFile.isEmpty()) return null; // 自定义临时目录 String customTempDir = "/opt/app/temp/uploads"; File dir = new File(customTempDir); if (!dir.exists()) { dir.mkdirs(); } File file = new File(customTempDir + "/" + UUID.randomUUID() + "." + FilenameUtils.getExtension(multipartFile.getOriginalFilename())); multipartFile.transferTo(file); System.out.println("File Path "+file.getAbsolutePath()); return uploadFile(file, partnerId); }
4. 验证生产环境磁盘空间与权限
- 检查
/tmp或自定义临时目录的磁盘是否已满 - 手动在目标目录创建文件,验证应用进程是否有读写权限
内容的提问来源于stack exchange,提问作者Najeeba Saidalavi
相关产品推荐
相关产品推荐

