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

Spring Boot文件上传异常:Multipart临时文件无法删除问题求助

Spring MVC文件上传「Failed to perform cleanup of multipart items」排查方案

问题明确

  • 浏览器上传文件至Spring MVC服务时,抛出Failed to perform cleanup of multipart items异常
  • 移除自定义JwtTokenFilter后上传恢复正常,确认异常由该过滤器引发
  • Windows 10/11系统下,手动删除系统临时目录中的上传临时文件时,提示文件被程序占用
  • 业务逻辑可正常返回结果,但Multipart上传生成的临时文件无法自动清理

核心原因分析

该异常本质是临时文件资源泄漏,过滤器的不当处理导致JVM进程持有临时文件的引用,无法释放。常见触发场景:

  1. 过滤器中直接读取原始请求体(request.getInputStream()/request.getReader()),消耗了请求流,导致Spring的MultipartResolver无法正确处理文件上传,或临时文件的输入流未被正常关闭
  2. 过滤器未正确包装Multipart请求,后续处理中临时文件的资源未被纳入Spring的生命周期管理
  3. 过滤器中打开的流资源未在请求结束后及时关闭,导致文件句柄泄漏

排查与解决步骤

1. 检查过滤器中请求体读取逻辑

如果过滤器需要解析JWT token而读取请求体,必须避免直接消耗原始请求流:

  • 先判断请求是否为Multipart类型(Content-Type以multipart/开头),若是则直接放行,让Spring优先处理文件上传,再进行token校验
  • 非Multipart请求,使用ContentCachingRequestWrapper包装请求,缓存请求体内容,确保后续处理能重复读取流

2. 确保流资源正确关闭

若过滤器中手动打开了输入流,必须在finally块中强制关闭,避免资源泄漏:

InputStream inputStream = null;
try {
    inputStream = request.getInputStream();
    // 处理逻辑
} finally {
    if (inputStream != null) {
        try {
            inputStream.close();
        } catch (IOException e) {
            // 日志记录
        }
    }
}

3. 调整过滤器执行顺序

确保JwtTokenFilter在MultipartFilter之后执行(如果项目中配置了MultipartFilter),让Spring先完成文件上传的解析和临时文件的创建,再执行token校验逻辑。

4. 验证Multipart配置

确认Spring配置中spring.servlet.multipart.cleanup-enabled为true(默认开启),同时检查临时文件目录的读写权限正常。

修正后的过滤器示例

public class JwtTokenFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 跳过Multipart请求,让Spring先处理文件上传
        if (isMultipartRequest(request)) {
            filterChain.doFilter(request, response);
            return;
        }

        // 非Multipart请求,用缓存包装类读取请求体
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
        String requestBody = IOUtils.toString(wrappedRequest.getContentAsByteArray(), StandardCharsets.UTF_8);
        
        // 解析JWT token逻辑...
        
        // 传递包装后的请求,确保后续流程正常
        filterChain.doFilter(wrappedRequest, response);
    }

    private boolean isMultipartRequest(HttpServletRequest request) {
        String contentType = request.getContentType();
        return contentType != null && contentType.startsWith("multipart/");
    }
}

内容的提问来源于stack exchange,提问作者gold-three

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 19:15:19