You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:21:48