提示:Spring Boot 文件上传接口 Postman 测试报错“Required request part ‘file’ is not present”的解决全过程
前言
提示:Required request part 'file' is not present
大家好,我是将军。最近在开发一个基于 Spring Boot 的项目时,遇到了一个让我头疼了两天的文件上传问题:使用 Postman 测试文件上传接口时,总是报错 Required request part 'file' is not present。这个错误看似简单,但排查起来却像剥洋葱,一层一层地深入。最终,我通过参考一篇简书文章(Spring Boot 文件上传解析器配置问题)和项目实际调试,找到了根源——Spring Boot 的默认 MultipartResolver 在某些版本下解析 multipart/form-data 请求时不稳定。以下是我从问题复现到彻底解决的全过程记录,希望能帮到遇到同样坑的开发者。
提示:以下是解决全过程
大家好,我是将军。最近在开发一个基于 Spring Boot 的项目时,遇到了一个让我头疼了两天的文件上传问题:使用 Postman 测试文件上传接口时,总是报错 Required request part 'file' is not present。这个错误看似简单,但排查起来却像剥洋葱,一层一层地深入。最终,我通过参考一篇简书文章(Spring Boot 文件上传解析器配置问题)和项目实际调试,找到了根源——Spring Boot 的默认 MultipartResolver 在某些版本下解析 multipart/form-data 请求时不稳定。以下是我从问题复现到彻底解决的全过程记录,希望能帮到遇到同样坑的开发者。
问题背景与复现
项目是一个分期申请管理系统,使用 Spring Boot 2.x(实际版本 1.4.2.RELEASE,稍后会提到版本影响)。接口是 /api/installmentApplication/importMarkProcessed,用于上传 Excel 文件批量处理分期标记。接口定义如下(简化版):
@PostMapping("/importMarkProcessed")
@RequiresRoles({"CUSTOMER_SERVICE", "CUSTOMER_SERVICE_MANAGER"})
public ResponseEntity<String> importMarkProcessed(@RequestParam("file") MultipartFile file) {
// 处理文件逻辑...
return ResponseEntity.ok("上传成功");
}
测试流程(Postman):
- 请求方式:POST
-
URL:
http://localhost:8080/api/installmentApplication/importMarkProcessed -
Body:form-data
- Key:
file(Type: File) - Value:选择本地 .xlsx 文件
- Key:
-
Headers:自动生成
Content-Type: multipart/form-data; boundary=...(无手动设置)
发送请求后,控制台直接抛出:
Required request part 'file' is not present
这个错误表示服务器端未接收到名为 file 的 multipart 部分。乍一看是客户端问题,但 Postman 配置明明正确啊!
初步排查:排除常见坑
我先从“万金油”解决方案入手,排查了以下几点(这些是网上最常见的建议):
-
Postman 配置检查:
- Key 名称严格为
file(小写,无空格)。 - 文件选择有效(非空 .xlsx 文件,大小 < 10MB)。
- Headers 中移除手动
Content-Type,让 Postman 自动处理。 - 生成 cURL 命令测试:
curl -X POST -F "file=@/path/to/file.xlsx" http://localhost:8080/...,结果相同错误。
- Key 名称严格为
-
服务器端基本配置:
-
application.properties(或 yml)添加:spring.servlet.multipart.enabled=true spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=10MB - 重启服务,测试其他文件上传接口(如
/submit),部分正常,但问题接口仍报错。
-
-
权限与拦截器检查:
- 接口有 Shiro
@RequiresRoles,确认 Postman 携带有效 token(通过登录接口获取)。 - 项目有自定义拦截器
MultipartLoggingInterceptor,但仅针对/submit,不影响当前路径。 - 启用 DEBUG 日志(
logging.level.org.springframework.web=DEBUG),日志显示请求到达控制器,但file参数为 null。
- 接口有 Shiro
排查了两天,这些都没问题。我开始怀疑是 Spring Boot 版本或底层解析器 bug。最终,在一次无意搜索中,找到了那篇简书文章,点亮了新思路:默认的 StandardServletMultipartResolver 在旧版 Spring Boot 中可能无法正确解析 multipart 请求,建议切换到 ***monsMultipartResolver。
深入分析:MultipartResolver 的“黑洞”
Spring Boot 的文件上传依赖 MultipartResolver 来解析 multipart/form-data。默认使用 StandardServletMultipartResolver(基于 Servlet 3.0+),但在 Spring Boot 1.x(如 1.4.2)中,它对某些边界情况(如自定义编码或大文件)处理不稳,导致参数“蒸发”。
-
为什么是这个版本问题?Spring Boot 2.x 优化了默认解析器,但 1.x 需手动配置
***monsMultipartResolver(基于 Apache ***mons FileUpload),它更鲁棒,支持更多场景。 -
项目确认:查看
pom.xml,parent 版本确为1.4.2.RELEASE。这解释了为什么其他接口偶尔正常(简单文件),但复杂路径(如带 Shiro 拦截)失败。
解决方案:一步步配置 ***monsMultipartResolver
基于文章思路,我本地化了配置,分三步实施。整个过程只需修改三个文件,重启即生效。
步骤 1: 添加依赖
在 pom.xml 的 <dependencies> 中添加 ***mons-fileupload(如果未存在):
<dependency>
<groupId>***mons-fileupload</groupId>
<artifactId>***mons-fileupload</artifactId>
<version>1.4</version>
</dependency>
位置:项目根目录 pom.xml。运行 mvn clean install 更新依赖。
步骤 2: 排除默认自动配置
在 application.yml(或 application.properties)中禁用默认 MultipartAutoConfiguration,避免冲突:
spring:
autoconfigure:
exclude: org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
位置:src/main/resources/application.yml(开发环境用 application-dev.yml)。这步关键,确保自定义 Bean 生效。
步骤 3: 注入自定义 MultipartResolver Bean
在 Web 配置类中添加 Bean。项目已有 WebConfig.java,直接扩展:
package ***.hyham.***mon.config.web;
import org.apache.***mons.logging.Log;
import org.apache.***mons.logging.LogFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.***mons.***monsMultipartResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMv***onfigurer;
@Configuration
public class WebConfig implements WebMv***onfigurer {
private static final Log log = LogFactory.getLog(WebConfig.class);
// 现有拦截器注入...
private final MultipartLoggingInterceptor loggingInterceptor;
public WebConfig(MultipartLoggingInterceptor loggingInterceptor) {
this.loggingInterceptor = loggingInterceptor;
}
@Bean(name = "multipartResolver")
public MultipartResolver multipartResolver() {
log.info("Loading the ***monsMultipartResolver");
***monsMultipartResolver resolver = new ***monsMultipartResolver();
resolver.setMaxUploadSize(10485760L); // 10MB
resolver.setDefaultEncoding("UTF-8"); // 防中文乱码
return resolver;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 现有拦截器配置...
registry.addInterceptor(loggingInterceptor).addPathPatterns("/api/installmentApplication/submit");
}
}
位置:src/main/java/***/hyham/***mon/config/web/WebConfig.java。添加后,日志会输出 “Loading the ***monsMultipartResolver”,确认生效。
测试验证与注意事项
配置完成后,重启项目(mvn spring-boot:run),Postman 测试:
- 上传相同 .xlsx 文件,接口返回 “上传成功”,日志显示
file参数非 null,大小正确。 - 额外测试:上传大文件(>5MB)、中文文件名,全正常。
注意事项:
- 版本适用:Spring Boot 1.x 必备,2.x 可选(默认已优化)。
- 权限检查:确保 Shiro 角色正确,否则请求被拦截。
-
文件目录:确认
${file.upload.dir:/uploads}目录有写权限(chmod 777 /uploads)。 - Excel 解析:上传文件需含 “案件号” 和 “申请日期” 表头,否则后续 POI 解析报错。
-
调试技巧:在控制器添加
log.info("File: {}", file.getOriginalFilename());,快速验证。
如果你的项目是 Spring Boot 2.x+,先试默认配置;否则,这个方案 100% 管用。
总结与感悟
这个 bug 让我深刻体会到:文件上传看似简单,实则涉及 Servlet、Spring 底层和客户端工具的完美协作。两天排查让我从 Postman 调到日志分析,再到源码深挖,最终靠一篇“新思路”文章解围。开发路上,多记录、多分享,才能少走弯路。
如果你也遇到类似问题,欢迎评论区交流!项目源码(脱敏版)可私信索要。点赞收藏不迷路,下篇见~
标签:Spring Boot, 文件上传, Postman, MultipartResolver, Java
相关阅读:
- Spring Boot 官方文件上传文档
- Apache ***mons FileUpload 指南