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

React对接Spring API:MultipartFile上传失败问题排查

React前端与Spring后端MultipartFile上传失败排查与修复

问题现象

React前端向Spring后端上传图片时,后端抛出org.springframework.web.multipart.MultipartException: Current request is not a multipart request错误,但用Postman测试相同接口完全正常。


原代码片段

Spring后端接口代码

@PostMapping("/save")
public ResponseEntity<?> save(@RequestParam(required = false) String folderId, @RequestParam MultipartFile multipartFile) throws IOException{
    // 文件夹存在校验
    int id = Integer.parseInt(folderId);
    Optional<Folder> folderOpt = folderService.get(id);
    if(folderOpt.isEmpty()){
        return new ResponseEntity<>("The folder does not exist", HttpStatus.NOT_FOUND);
    }
    Folder folder = folderOpt.get();

    // 图片有效性校验
    BufferedImage bi = ImageIO.read(multipartFile.getInputStream());
    if (bi == null){
        return new ResponseEntity("Image does not valid", HttpStatus.BAD_REQUEST);
    }
    Map result = cloudinaryService.upload(multipartFile);

    // 保存到数据库
    Image img = new Image(
        (String)result.get("original_filename"),
        (String)result.get("url"),
        (String)result.get("public_id")
    );
    img.setFolder(folder);
    imageService.save(img);
    return new ResponseEntity<>(HttpStatus.OK);
}

React前端组件代码

const [imageSelected,setImageSelected] = useState("")
const uploadImage = (files) =>{
    const formData = new FormData();
    formData.append("file", files[0]);

    console.log(formData)   
    ImagenServices.postImage(formData,id)
}

return(
    <div className={Styles.container}>
        <div>
            <input type="file" id="myFileField" onChange={(event) => {setImageSelected(event.target.files)}}/>
            <button onClick={() => uploadImage(imageSelected)}>Upload image</button>
        </div>
    </div>
)

PostImage服务代码

async postImage(file,idFolder){
    let request = await fetch(REST_API_URL + "/save",{
        method: "POST",
        body:{
            'folderId': idFolder,
            'multipartFile': file
        },
        headers:{
            'Accept': 'application/json, text/plain, */*',
            'Content-Type': false
        }}, 
    )
}

报错信息

ERROR 95787 --- [io-8080-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Current request is not a multipart request] with root cause

org.springframework.web.multipart.MultipartException: Current request is not a multipart request
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValueInternal(RequestParamMethodArgumentResolver.java:210) ~[spring-web-5.3.22.jar:5.3.22]


错误原因分析

  1. FormData参数名不匹配:后端@RequestParam接收的参数名是multipartFile,但前端append的是file,导致后端无法识别文件参数。
  2. 请求body格式错误:PostImage服务中把FormData嵌套在了普通对象里,而非直接作为请求body,浏览器无法识别为multipart请求。
  3. Content-Type设置错误:手动设置Content-Type: false会破坏浏览器自动生成的multipart/form-data请求头(包含必要的boundary信息)。
  4. useState初始值不合理:imageSelected初始值设为空字符串,而event.target.files是FileList类型,类型不匹配可能导致后续逻辑异常。

修正后的代码

React前端组件代码

const [imageSelected, setImageSelected] = useState(null); // 初始值设为null,匹配FileList类型

const uploadImage = () => {
  if (!imageSelected) return; // 增加文件选择校验
  const formData = new FormData();
  formData.append("multipartFile", imageSelected[0]); // 参数名与后端保持一致
  formData.append("folderId", id); // 将folderId也加入FormData

  ImagenServices.postImage(formData);
};

return (
  <div className={Styles.container}>
    <div>
      <input 
        type="file" 
        id="myFileField" 
        onChange={(event) => setImageSelected(event.target.files)} 
      />
      <button onClick={uploadImage}>Upload image</button>
    </div>
  </div>
);

PostImage服务代码

async postImage(formData) {
  const request = await fetch(REST_API_URL + "/save", {
    method: "POST",
    body: formData, // 直接传递FormData实例
    headers: {
      'Accept': 'application/json, text/plain, */*'
      // 不要手动设置Content-Type,浏览器会自动添加正确的multipart/form-data头
    }
  });
  
  // 可根据需求添加响应处理逻辑
  const response = await request.json();
  return response;
}

关键修复点说明

  • 参数名一致性:确保FormData中append的参数名与后端@RequestParam的参数名完全一致。
  • 正确传递FormData:必须将FormData直接作为fetch的body,不能嵌套在其他对象中,否则浏览器无法识别为multipart请求。
  • 自动处理Content-Type:当请求body是FormData时,浏览器会自动生成包含boundary的multipart/form-data请求头,手动设置反而会导致请求格式错误。
  • 类型匹配的状态初始值:将imageSelected初始值设为null,避免与FileList类型冲突。

内容的提问来源于stack exchange,提问作者ddi02

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 05:40:31