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

多Blob图片上传单文件正常、多文件报错问题排查求助

多图片Blob上传失败,单文件正常的排查与解决

我正在开发网站的多图片上传功能,采用Blob格式将文件上传至服务器。单文件上传可正常运行,但上传2个及以上文件时会出现错误——服务端检查req相关属性均返回undefined,仅多文件上传会触发该问题。


前端状态定义

type BlobNull = {
    0: Blob | null
    1: Blob | null
    2: Blob | null
    3: Blob | null
}
const [blobs, setBlobs] = React.useState < BlobNull > ({
    0: null,
    1: null,
    2: null,
    3: null,
})

const [catalog, setCatalog] = React.useState({
    ProductName: "",
    cShopVisiblity: true,
    Delivery: true,
    ItemPrice: "",
    Quantitiy: "",
    Notes: "Notes"
})

前端提交处理函数

const handleAdd = async () => {
    startLoading();
    try {
        if (Object.values(catalog).every(val => val.toString().trim() !== "")) {
            const formData = new FormData();
            Object.keys(catalog).forEach(key => formData.append(key, catalog[key]));
            Object.values(blobs).filter(val => val !== null).forEach((blob, id) => formData.append(`Img`, blob))

            const { data, isOK } = await catalogService.add(formData);
            if (isOK) {
                addToastMsg(`Details saved : ${data.ProductName} ${data.Quantitiy}`, "success");
                setCatalog({
                    ProductName: "",
                    cShopVisiblity: true,
                    Delivery: true,
                    ItemPrice: "",
                    Quantitiy: "",
                    Notes: "Notes"
                });

                setOpen(false);
            } else {
                throw new Error("Internal server error");
            }
        } else {
            addToastMsg("Please fill all the fields required.", "warning");
        }

    } catch (e) {
        console.error("error saving form", e);
        addToastMsg(
            "Unable to save details, please re validate entered values",
            "error"
        );
    }
    endLoading();
}

后端接口代码

exports.add = async (req, res) => {
    try {
        // if (req.file) console.log("file");
        // if (req.files) console.log("files");
        // if (req.Img) console.log("Img");
        // if (req.data) console.log("data");
        if (req.files?.length > 1 && Array.isArray(req.files['Img'])) {
            multiUpload(req, res, async function (err) {
                if (err) {
                    return res.status(400).json({ message: 'Error uploading files' });
                }
                const files = req.files;
                const imageBuffers = files.map((file, id) => ({ [`Img${id > 0 ? id : ''}`]: Buffer.from(file.buffer) }))
                const catalog = await catalogsModel.create({ ...req.body, ...imageBuffers });
                res.status(201).json({
                    success: true,
                    data: catalog,
                });
            });
        } else {
            singleUpload(req, res, async function (err) {
                if (err) {
                    // handle the error here
                    return res.status(400).json({ message: 'Error uploading file' });
                }
                if (req.file) {
                    const imageBuffer = Buffer.from(req.file.buffer);
                    const catalog = await catalogsModel.create({ ...req.body, Img: imageBuffer });
                    res.status(201).json({
                        success: true,
                        data: catalog,
                    });
                } else {
                    const catalog = await catalogsModel.create(req.body);
                    res.status(201).json({
                        success: true,
                        data: catalog,
                    });
                }
            });
        }
    } catch (error) {
        console.log("API error", error);
        if (!res.headersSent) {
            res.send(500).json({
                success: false,
                error: "Server error",
            });
        }
        return;
    }
};

问题核心原因

  1. 后端逻辑执行顺序错误:你先判断req.files?.length > 1 && Array.isArray(req.files['Img']),但此时multiUpload文件上传中间件还未执行,req.files尚未被赋值,必然是undefined。这会导致代码直接进入singleUpload分支,但singleUpload仅支持单文件处理,多文件传入后无法正确解析,最终req.file和req.files全为undefined。

  2. 中间件拆分冗余:分开使用singleUpload和multiUpload不仅增加复杂度,还会导致多文件场景下中间件不匹配,无法正确解析请求。


修复方案

1. 调整后端逻辑顺序,统一中间件

移除先判断文件数量的逻辑,先执行支持多文件的上传中间件,再处理业务数据。以multer为例:

// 假设已配置multer存储
const upload = multer({ storage: ... });

// 接口直接使用支持多文件的中间件,限制最多4个文件
exports.add = upload.array('Img', 4), async (req, res) => {
    try {
        // 中间件执行后,req.files为上传的文件数组,req.body为表单数据
        let imageBuffers = {};
        if (req.files?.length) {
            req.files.forEach((file, id) => {
                imageBuffers[`Img${id > 0 ? id : ''}`] = Buffer.from(file.buffer);
            });
        }
        const catalog = await catalogsModel.create({ ...req.body, ...imageBuffers });
        res.status(201).json({ success: true, data: catalog });
    } catch (error) {
        console.log("API error", error);
        if (!res.headersSent) {
            res.status(500).json({ success: false, error: "Server error" });
        }
    }
};

2. 前端补充文件名(可选)

给FormData中的Blob添加文件名,避免部分中间件解析异常:

Object.values(blobs).filter(val => val !== null).forEach((blob, id) => {
    // 自定义文件名,后缀可根据实际文件类型调整
    formData.append(`Img`, blob, `product-image-${id}.png`);
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 22:49:58