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

MERN电商项目更新产品时无法获取req.body数据求助

问题描述

在MERN电商项目中更新产品时,点击更新按钮无报错,但页面显示旧数据、MongoDB未发生变更;Postman测试同样无报错但返回旧数据。后端控制器打印req.body.name显示undefined。


核心原因与解决方案

1. 后端未配置Multipart数据解析(关键问题)

前端通过FormData发送multipart/form-data类型数据,默认的express.json()中间件无法解析,必须用multer处理文件与文本字段。

修改后端路由配置(示例:productRoutes.js)

import express from 'express';
import { updateproducts } from '../controllers/productController.js';
import multer from 'multer';
import path from 'path';

// 配置multer文件存储
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const uploadPath = path.resolve('./uploads');
    cb(null, uploadPath); // 确保uploads文件夹存在并有权限
  },
  filename: (req, file, cb) => {
    cb(null, `${Date.now()}-${file.originalname}`); // 避免文件名重复
  }
});

const upload = multer({ storage: storage });
const router = express.Router();

// 用upload.array('images')接收多文件上传,对应前端的FormData.append('images', file)
router.put('/update-product/:id', upload.array('images'), updateproducts);

export default router;

修改后端控制器

import Category from "../models/categoryModel.js";
import productModel from "../models/productModel.js";
import fs from 'fs';
import path from 'path';

export const updateproducts = async (req, res) => {
    try {
        // 现在req.body可获取文本字段,req.files为上传的文件数组
        console.log("产品名称: ", req.body.name);
        
        // 整理更新数据,仅更新前端传递的字段
        const updateData = {
            name: req.body.name,
            description: req.body.description,
            mrp: req.body.mrp,
            category: req.body.category,
            InStock: parseInt(req.body.InStock) // 转数字匹配数据库类型
        };

        // 处理图片逻辑
        if (req.files?.length > 0) {
            // 解析前端传递的删除图片列表,删除服务器文件
            if (req.body.DeletedImages) {
                const deletedImages = JSON.parse(req.body.DeletedImages);
                deletedImages.forEach(img => {
                    const filePath = path.resolve(`./uploads/${img}`);
                    if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
                });
            }
            // 合并原有未删除图片与新上传图片
            const existingImages = JSON.parse(req.body.existingImages) || [];
            const newImageNames = req.files.map(file => file.filename);
            updateData.images = [...existingImages, ...newImageNames];
        }

        // 执行更新,开启runValidators确保字段验证
        const product = await productModel.findByIdAndUpdate(
            req.params.id,
            updateData,
            { new: true, runValidators: true }
        );

        if (!product) {
            return res.status(404).json({ success: false, error: '产品未找到或无法更新' });
        }

        res.json({ success: true, message: '产品更新成功', updatedProduct: product });
    } catch (error) {
        console.error(error);
        res.status(500).json({ success: false, error: '服务器内部错误' });
    }
}; 

2. 前端代码修正

分离原有图片与新上传文件,传递删除列表

// 更新产品函数
const handleUpdate = async (e) => {
    e.preventDefault();
    try {
        const productData = new FormData();
        // 传递文本字段
        productData.append("name", name);
        productData.append("description", description);
        productData.append("mrp", mrp);
        productData.append("category", category);
        productData.append("InStock", InStock);
        // 传递删除的图片列表(转JSON字符串)
        productData.append("DeletedImages", JSON.stringify(DeletedImages));
        // 分离原有图片(字符串文件名)与新上传文件(File对象)
        const existingImages = selectedImages.filter(img => typeof img === 'string');
        const newImages = selectedImages.filter(img => typeof img !== 'string');
        // 传递原有未删除图片
        productData.append("existingImages", JSON.stringify(existingImages));
        // 仅追加新上传的文件
        newImages.forEach(img => productData.append("images", img));

        const { data } = await axios.put(`/api/v1/product/update-product/${params.id}`, productData, {
            headers: { 'Content-Type': 'multipart/form-data' }
        });

        // 修正toast逻辑
        if (!data?.success) {
            toast.error(data?.message);
        } else {
            toast.success("产品更新成功");
            navigate("/dashboard/manage.vision/admin/products");
        }
    } catch (error) {
        console.log(error);
        toast.error("更新失败,请重试");
    }
};

修复图片预览逻辑(区分原有图片与新上传文件)

{selectedImages &&
    selectedImages.map((image, index) => {
        const imgSrc = typeof image === 'string' 
            ? `http://localhost:3000/uploads/${image}` 
            : URL.createObjectURL(image);
        return (
            <div key={index} className="image">
                <img src={imgSrc} alt="产品图片" className="primg" />
                <FontAwesomeIcon icon={faTrashCan} className="prdele" onClick={() => deleteHandler(image)} />
                <p className="imgno">{index + 1}</p>
            </div>
        );
    })}

3. 额外检查项

  • 确保后端uploads文件夹存在且有读写权限
  • 验证MongoDB中产品_id与前端params.id完全一致
  • 检查前端下拉选项的value类型与数据库字段类型匹配(如InStock是数字则传递数字)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 18:14:49