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

Node.js上传图片至GCP存MongoDB遇404及ERR_HTTP_HEADERS_SENT错误求助

问题分析与解决方案

错误根源

  1. 重复发送响应(ERR_HTTP_HEADERS_SENT):uploadMultipleImage函数中,当单张图片上传失败时直接调用resolve(false),但Promise.all仍在处理其他异步任务,后续代码会继续执行到resolve(fileArr),导致Promise被多次触发。这会让接口逻辑同时执行错误响应和成功响应的返回操作,进而触发Cannot set headers after they are sent to the client错误。
  2. 404错误:主要因上述Promise逻辑混乱导致请求处理流程异常,也需排查接口路由配置是否与请求路径匹配。

修复方案

1. 修正多图上传的Promise逻辑

避免多次调用resolve,改用抛出错误+统一捕获的方式处理上传失败场景,确保Promise只被触发一次。

2. 简化GCP单文件上传代码

移除冗余的Promise嵌套,直接返回上传结果或抛出错误,提升代码可读性和稳定性。


修复后的完整代码

接口处理代码(无需修改)

module.exports.addProductImage = async (request, response, next) => {
    try {
        const { color } = request.body;
        const { id } = request.params;

        if (!request.files?.images) {
            return response.status(400).json({
                status: false,
                message: "No image provided",
                data: null,
            });
        }

        const imagesArr = await uploadMultipleImage(request.files.images, []);
        if (!imagesArr) {
            return response.status(400).json({
                status: false,
                message: "Error While Adding Product Image",
                data: null,
            });
        }
        const addProductQuantity = await Product.findOneAndUpdate(
            {
                _id: id,
            },
            {
                $push: {
                    singleImage: {
                        color: color,
                        images: imagesArr[0],
                    },
                    images: {
                        color: color,
                        images: imagesArr,
                    },
                },
            },
            {
                new: true,
            },
        );

        response.json({
            status: true,
            message: "Product Image Added Successfully",
            data: addProductQuantity,
        });

    } catch (e) {
        console.log("e", e);
        return response.status(500).json({
            status: false,
            message: "Something went wrong. Please try again",
            data: null,
        });
    }
};

GCP上传代码(修正后)

// 简化单文件上传逻辑,直接返回文件名或抛出错误
const uploadFileToGCS = async (fileName, fileData) => {
    try {
        const file = bucket.file(fileName);
        const options = {
            resumable: true,
            // predefinedAcl: "publicRead",
        };
        await file.save(fileData.data, options);
        return fileName; // 上传成功返回文件名
    } catch (error) {
        console.log("单文件上传失败:", error);
        throw new Error("图片上传失败"); // 上传失败抛出错误,由上层捕获
    }
};

const uploadMultipleImage = async (images, oldArr) => {
    let fileArr = oldArr;
    try {
        // Promise.all确保所有图片上传完成,任一失败则进入catch
        const uploadedFileNames = await Promise.all(
            images.map(async (element) => {
                const fileName = `product/${new Date().getTime()}${path.extname(element.name)}`;
                return await uploadFileToGCS(fileName, element);
            })
        );
        fileArr.push(...uploadedFileNames);
        return fileArr;
    } catch (error) {
        console.error("多图上传失败:", error);
        return false; // 上传失败返回false,由接口层处理错误响应
    }
};

额外检查项

  • 确认接口路由配置与请求路径完全匹配,避免路由不匹配导致的404错误。
  • 验证GCP存储桶权限及初始化配置,确保服务账号拥有上传文件的权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 10:33:29