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

使用multer上传文件时如何跳过已存在于磁盘的重复文件?

问题原因

你代码的核心问题是中间件执行顺序错误:
multer的upload.array('imgCollection')是路由前置中间件,请求到达/upload接口时,会先执行multer逻辑把所有文件写入磁盘覆盖同名文件,全部写入完成后才会进入你写的MongoDB校验逻辑,此时旧文件已经被覆盖,校验自然失去意义。

修复方案

方案1:使用multer内置fileFilter做前置校验(推荐)

multer提供fileFilter配置项,支持在文件写入磁盘之前做自定义逻辑拦截,你可以在该环节先查询MongoDB判断文件是否存在,存在则直接拒绝写入:

// 仅展示修改部分,其余逻辑保留
const fileFilter = async (req, file, cb) => {
  const fileFullName = 'public/' + file.originalname
  try {
    const existFile = await Attachment.findOne({ file_name: fileFullName })
    if (existFile) {
      // 存在同名文件,拦截写入
      cb(new Error(`文件${fileFullName}已存在`), false)
      return
    }
    // 无重复,允许写入
    cb(null, true)
  } catch (err) {
    cb(err, false)
  }
}

const upload = multer({
  storage: storage,
  fileFilter: fileFilter // 注入自定义校验逻辑
});

// 路由逻辑优化
router.post('/upload', upload.array('imgCollection'), async (req, res) => {
  try {
    // 批量写入数据库,用Promise.all确保所有写入完成再返回响应
    const savePromises = req.files.map(file => {
      const attachment = new Attachment({
        file_name: 'public/' + file.filename
      })
      return attachment.save()
    })
    await Promise.all(savePromises)
    res.status(201).json({ message: '文件保存成功' })
  } catch (e) {
    // 错误处理:如果部分文件已经写入,删除残留文件
    const fs = require('fs/promises')
    if (req.files?.length) {
      for (const file of req.files) {
        await fs.unlink(file.path).catch(() => {})
      }
    }
    res.status(400).json({ message: e.message })
  }
})

方案2:新增预校验接口(适合大文件场景)

如果上传的是大文件,先传文件再校验会浪费带宽,你可以新增一个预校验接口:

  • 前端选完文件后,先把所有文件名传给预校验接口,后端查MongoDB直接返回是否有重复
  • 确认无重复后再调用上传接口传文件,优化用户体验
其他代码问题说明

你原路由中用reqFiles.map(async name => { await attachment.save() })的写法不会等待所有数据库写入操作完成就会返回响应,可能出现前端收到成功提示但数据库实际未写入的问题,修复后用Promise.all批量等待所有写入操作完成再返回。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 12:27:06