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

如何使用Multer S3将多文件同时上传至多个S3存储桶?

问题描述

我见过很多关于使用Multer上传多文件的问题,我本地已经实现了该功能,现在我的疑问是*是否可以使用Multer将多文件上传到不同的存储中?*目前我将文件上传到S3的一个存储桶,现在我希望在同一次请求中,将相同的文件同时上传到S3的bucket#1和bucket#2两个存储桶。

以下是我当前使用Multer S3实现多文件上传的代码:

const uploadsBusinessGallery = multer({
  storage: multerS3({
    s3: s3.s3_BUCKET_TEST,
    bucket: process.env.AWS_BUCKET_BUCKET_TEST,
    acl: "public-read",
    contentType: multerS3.AUTO_CONTENT_TYPE,
    key: function (req, file, cb) {
      const pathForder = req.url.split("/");

      var newFileName =
        path.basename(file.originalname, path.extname(file.originalname)) +
        path.extname(file.originalname);
      var fullPath =
        pathForder[pathForder.length - 1].replace("%20", " ") +
        "/" +
        newFileName;
      console.log(fullPath);
      cb(null, fullPath);
    },
  }),
  /*   limits: { fileSize: 2000000 }, // In bytes: 2000000 bytes = 2 MB
   */ fileFilter: function (req, file, cb) {
    checkFileType(file, cb);
  },
}).array("galleryImage", 500);

如您所见,当前我将文件上传到名为AWS_BUCKET_BUCKET_TEST的存储桶,我想要将相同的文件上传到S3的第二个存储桶。

我尝试了先将文件上传到AWS_BUCKET_BUCKET_TEST(bucket#1)后,复用同一份请求上传到第二个存储桶:
我的思路是:当Multer将文件上传到bucket#1后,将相同的请求传给另一个Multer实例,上传到第二个存储桶

function uploadFiles(req, res) {
  uploadsBusinessGallery(req, res, (error) => {
    if (error) {
      console.log("errors en la integración", error);
      return;
    } else {
      // If File not found
      if (req.files === undefined) {
        console.log("Error: No File Selected!");
      } else {
        // If Success
        integration(req,res);
      }
    }
  });
const integration = (req, res) => {
    uploadsFilesIntegration(req, res, (error) => {
    console.log("*********************************");
    console.log("Backend integration");
    if (error) {
      console.log("errors en la integración", error);
      return;
    } else {
      // If File not found
      if (req.files === undefined) {
        console.log("Error: No File Selected!");
      } else {
        // If Success
        console.log('Archivos integrados')
      }
    }
  });
};

负责上传文件到名为AWS_BUCKET_CD的bucket#2的Multer配置如下:

const uploadsFilesIntegration = multer({
  storage: multerS3({
    s3: s3.s3_CD,
    bucket: process.env.AWS_BUCKET_CD,
    acl: "public-read",
    contentType: multerS3.AUTO_CONTENT_TYPE,
    key: function (req, file, cb) {
      const pathForder = "folder1/subfolder2/subfolder3";
        console.log('s3.s3_CD',s3.s3_CD)
      var newFileName =
        path.basename(file.originalname, path.extname(file.originalname)) +
        path.extname(file.originalname);
      var fullPath =
        pathForder +
        "/" +
        newFileName;
      console.log(fullPath);
      cb(null, fullPath);
    },
  }),
  /*   limits: { fileSize: 2000000 }, // In bytes: 2000000 bytes = 2 MB
   */ fileFilter: function (req, file, cb) {
    checkFileType(file, cb);
  },
}).array("galleryImage", 500);

但是我发现,当Multer完成bucket#1的文件上传后,会修改请求对象,导致第二个Multer实例无法读取到文件,无法完成bucket#2的上传。
我尝试过克隆请求对象传给不同的Multer实例但没有成功,也尝试过为单个Multer配置多个存储,但都没有找到可行的实现方案。
恳请各位帮忙提供解决方案,非常感谢。
备注:两个Multer实例使用相同的fieldName,因为我需要将相同的文件上传到两个存储桶。


解决方案

你遇到的问题核心原因是:HTTP 请求的文件流是一次性的,第一个 Multer 实例处理上传时已经将流消费完毕,第二个实例自然读取不到任何文件内容,复用或浅克隆请求都无法解决这个问题。以下是两种可行的实现方案:

方案一:自定义 Multer 存储,单次请求同时上传两个桶(推荐)

直接实现自定义的 Multer 存储逻辑,在文件流处理阶段同时往两个 S3 桶上传内容,不需要重复处理请求流,性能最优。

const multer = require('multer');
const multerS3 = require('multer-s3');
// 提前初始化好你的两个S3实例:s3.s3_BUCKET_TEST、s3.s3_CD

// 自定义双桶存储逻辑
const dualS3Storage = {
  _handleFile: function (req, file, cb) {
    // 并行执行两个桶的上传任务
    const uploadBucket1 = new Promise((resolve, reject) => {
      multerS3({
        s3: s3.s3_BUCKET_TEST,
        bucket: process.env.AWS_BUCKET_BUCKET_TEST,
        acl: "public-read",
        contentType: multerS3.AUTO_CONTENT_TYPE,
        key: function (req, file, cb) {
          const pathForder = req.url.split("/");
          const newFileName = path.basename(file.originalname, path.extname(file.originalname)) + path.extname(file.originalname);
          const fullPath = pathForder[pathForder.length - 1].replace("%20", " ") + "/" + newFileName;
          cb(null, fullPath);
        }
      })._handleFile(req, file, (err, info) => err ? reject(err) : resolve(info))
    })

    const uploadBucket2 = new Promise((resolve, reject) => {
      multerS3({
        s3: s3.s3_CD,
        bucket: process.env.AWS_BUCKET_CD,
        acl: "public-read",
        contentType: multerS3.AUTO_CONTENT_TYPE,
        key: function (req, file, cb) {
          const pathForder = "folder1/subfolder2/subfolder3";
          const newFileName = path.basename(file.originalname, path.extname(file.originalname)) + path.extname(file.originalname);
          const fullPath = pathForder + "/" + newFileName;
          cb(null, fullPath);
        }
      })._handleFile(req, file, (err, info) => err ? reject(err) : resolve(info))
    })

    // 等待两个桶都上传完成后回调
    Promise.all([uploadBucket1, uploadBucket2])
      .then(([res1, res2]) => cb(null, {bucket1: res1, bucket2: res2}))
      .catch(err => cb(err))
  },
  _removeFile: function (req, file, cb) {
    // 可选实现:上传出错时删除已上传的文件,避免脏数据
    cb(null)
  }
}

// 初始化Multer实例,使用自定义双桶存储
const uploadToDualBuckets = multer({
  storage: dualS3Storage,
  fileFilter: (req, file, cb) => checkFileType(file, cb)
}).array("galleryImage", 500)

使用时直接调用uploadToDualBuckets中间件处理请求即可,req.files中会同时保留两个存储桶的上传结果。

方案二:先缓存文件再分别上传(适合小文件场景)

如果不想自定义存储,也可以先将文件缓存到服务器内存/本地临时目录,再调用AWS S3 SDK分别上传到两个桶:

// 配置内存存储,先把文件读到内存中
const memoryUpload = multer({
  storage: multer.memoryStorage(),
  fileFilter: (req, file, cb) => checkFileType(file, cb)
}).array("galleryImage", 500)

async function uploadFiles(req, res) {
  memoryUpload(req, res, async (err) => {
    if (err) return res.status(500).send('文件读取失败:' + err.message)
    if (!req.files || req.files.length === 0) return res.status(400).send('未选择上传文件')

    try {
      // 遍历所有文件,并行上传到两个桶
      const uploadTasks = req.files.map(file => {
        // 上传到bucket1
        const task1 = s3.s3_BUCKET_TEST.upload({
          Bucket: process.env.AWS_BUCKET_BUCKET_TEST,
          Key: `${req.url.split("/").pop().replace("%20", " ")}/${file.originalname}`,
          Body: file.buffer,
          ACL: 'public-read',
          ContentType: file.mimetype
        }).promise()
        // 上传到bucket2
        const task2 = s3.s3_CD.upload({
          Bucket: process.env.AWS_BUCKET_CD,
          Key: `folder1/subfolder2/subfolder3/${file.originalname}`,
          Body: file.buffer,
          ACL: 'public-read',
          ContentType: file.mimetype
        }).promise()
        return Promise.all([task1, task2])
      })

      await Promise.all(uploadTasks)
      res.status(200).send('所有文件已上传到两个存储桶')
    } catch (uploadErr) {
      res.status(500).send('上传失败:' + uploadErr.message)
    }
  })
}

如果上传的文件体积较大,可以将内存存储换成multer.diskStorage缓存到本地磁盘,所有上传完成后再删除本地临时文件即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 09:57:03