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

React+Axios向Spring Boot传递MultipartFile数据失败求助

React + Axios 上传FormData到Spring Boot报错不支持application/octet-stream

问题场景

用React结合Axios向Spring Boot后端发送包含JSON数据和图片的FormData,后端接口已实现,但前端请求报错提示不支持Content-Type 'application/octet-stream',但浏览器开发者工具显示请求的Content-Type是multipart/form-data。用Postman测试接口能成功将数据存入数据库,但前端始终无法正常提交。

后端代码

@PostMapping("/meals")
public ResponseEntity<String> createMeal( MultipartFile [] file, @RequestPart("meal") Meal meal, @RequestPart(value = "image", required = false) MultipartFile imageFile) {    

    Meal savedMeal = authService.saveMeal(meal, imageFile);
    if (savedMeal != null) {
        return ResponseEntity.ok("Meal created successfully.");
    } else {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error creating the meal.");
    }
}

前端代码

const [mealData, setMealData] = React.useState({
    name: '',
    calories: 0,
    protein:0,
    fat:0,
    description: '',
    image: null, // 存储选中的图片文件
});

function handleImage(e){
    const image = e.target.files[0];
    setMealData({...mealData,image});
}
function handleChange(e) {
    const { name, value } = e.target;
    setMealData({ ...mealData, [name]: value });
}

const handleSubmit = async (event) => {
    event.preventDefault();

    try {
        const meal = {
            name: mealData.name,
            description: mealData.description,
            protein: mealData.protein,
            fat: mealData.fat,
            calories: mealData.calories,
        };

        const formData = new FormData();

        formData.append("meal", JSON.stringify(meal));
        formData.append("image", mealData.image);

        console.log(JSON.stringify(meal));
        console.log(mealData.image);

        const res = await axios.post("http://localhost:8080/auth/meals", formData, {
            headers: {
                "Content-Type": "multipart/form-data", // 手动设置Content-Type
            },
        });
    } catch (e) {
        console.log(e);
    }
};

问题原因

  1. 手动设置Content-Type丢失boundary:Axios会自动为multipart/form-data请求生成带boundary的Content-Type(比如multipart/form-data; boundary=----WebKitFormBoundaryxxx),手动设置后会丢失boundary,导致后端无法正确解析表单数据。
  2. JSON数据未指定Content-Type:前端直接把JSON字符串append到FormData,后端默认会把它当成application/octet-stream处理,无法解析为Meal对象。
  3. 后端多余参数导致解析冲突:方法中的MultipartFile [] file参数未指定@RequestPart,没有对应前端的字段,会干扰Spring的参数解析逻辑。

修复方案

1. 后端代码调整

移除多余的MultipartFile [] file参数(如果不需要接收多文件的话),确保参数都有明确的@RequestPart注解:

@PostMapping("/meals")
public ResponseEntity<String> createMeal(
    @RequestPart("meal") Meal meal, 
    @RequestPart(value = "image", required = false) MultipartFile imageFile) {    

    Meal savedMeal = authService.saveMeal(meal, imageFile);
    if (savedMeal != null) {
        return ResponseEntity.ok("Meal created successfully.");
    } else {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error creating the meal.");
    }
}

2. 前端代码调整

  • 移除手动设置的Content-Type,让Axios自动处理;
  • 将JSON数据包装成Blob并指定application/json类型,确保后端能正确解析:
const handleSubmit = async (event) => {
    event.preventDefault();

    try {
        const meal = {
            name: mealData.name,
            description: mealData.description,
            protein: mealData.protein,
            fat: mealData.fat,
            calories: mealData.calories,
        };

        const formData = new FormData();
        // 将JSON转为Blob并指定Content-Type
        formData.append("meal", new Blob([JSON.stringify(meal)], { type: "application/json" }));
        // 仅当图片存在时再添加,避免空值
        if (mealData.image) {
            formData.append("image", mealData.image);
        }

        console.log(JSON.stringify(meal));
        console.log(mealData.image);

        // 移除手动设置的headers,Axios自动处理Content-Type
        const res = await axios.post("http://localhost:8080/auth/meals", formData);
        console.log("提交成功:", res.data);
    } catch (e) {
        console.error("提交失败:", e);
    }
};

额外注意点

  • 确保后端的Meal实体类有无参构造函数和完整的getter/setter方法,否则Spring无法完成JSON到对象的转换;
  • 前端处理数值类型(如calories、protein)时,确保是数字而非字符串,避免后端类型不匹配报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 07:38:14