You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用multer-storage-cloudinary实现Cloudinary图片删除功能?

解决multer-storage-cloudinary上传后无法获取public_id进行图片删除的问题

核心问题在于你没有把Cloudinary返回的public_id存储到数据库中——而这个值正是调用destroy方法删除图片的关键。下面是一步步的解决方案:

第一步:修改上传逻辑,保存public_id到数据库

multer-storage-cloudinary实际上已经把public_id放在了req.file.filename里(因为你设置了folder: "works",所以这个值是带文件夹路径的完整public_id,比如works/ujrrf13kyil8l5rjccwf)。你需要把这个字段和图片URL一起存入数据库:

首先确保你的Post模型中添加了img_public_id字段(字符串类型),然后修改上传路由:

router.post('/', withAuth, imgUpload.single('work-img'), (req, res) => {
  console.log(req.file);
  Post.create({ 
    title: req.body.title, 
    dimension: req.body.dimensions, 
    description: req.body.description, 
    media: req.body.media, 
    img_url: req.file.path, 
    img_public_id: req.file.filename, // 新增:保存public_id到数据库
    user_id: req.session.user_id 
  })
  .then((dbPostData) => res.json(dbPostData))
  .catch((err) => { console.log(err); res.status(500).json(err); });
});

第二步:更新路由中删除旧图片并替换为新图片

在更新时,先查询旧帖子的img_public_id,调用Cloudinary的destroy方法删除旧图,再更新数据库中的新图片信息:

router.put('/:id', withAuth, imgUpload.single('work-img'), async (req, res) => {
  try {
    // 1. 查询旧帖子数据
    const oldPost = await Post.findByPk(req.params.id);
    if (!oldPost) {
      return res.status(404).json({ message: 'No post found with this id' });
    }

    // 2. 准备更新的基础数据
    const updateData = {
      title: req.body.title,
      dimension: req.body.dimensions,
      description: req.body.description,
      media: req.body.media
    };

    // 3. 如果用户上传了新图片,删除旧图并添加新图信息
    if (req.file) {
      // 调用Cloudinary API删除旧图片
      await cloudinary.uploader.destroy(oldPost.img_public_id);
      // 更新图片URL和public_id
      updateData.img_url = req.file.path;
      updateData.img_public_id = req.file.filename;
    }

    // 4. 执行数据库更新
    const [updatedRows] = await Post.update(updateData, { 
      where: { id: req.params.id } 
    });

    if (updatedRows === 0) {
      return res.status(404).json({ message: 'No post found with this id' });
    }

    // 返回更新后的完整帖子数据
    const updatedPost = await Post.findByPk(req.params.id);
    res.json(updatedPost);
  } catch (err) {
    console.log(err);
    res.status(500).json(err);
  }
});

第三步:删除路由中同时删除Cloudinary图片和数据库记录

如果需要删除帖子,记得先删除对应的Cloudinary图片:

router.delete('/:id', withAuth, async (req, res) => {
  try {
    const post = await Post.findByPk(req.params.id);
    if (!post) {
      return res.status(404).json({ message: 'No post found with this id' });
    }

    // 先删除Cloudinary上的图片
    await cloudinary.uploader.destroy(post.img_public_id);
    // 再删除数据库中的帖子
    await Post.destroy({ where: { id: req.params.id } });

    res.json({ message: 'Post and associated image deleted successfully' });
  } catch (err) {
    console.log(err);
    res.status(500).json(err);
  }
});

关键说明

  • req.file.filename就是Cloudinary的完整public_id(包含你设置的文件夹路径),直接用来调用destroy方法即可。
  • 使用async/await可以让异步操作更清晰,避免回调嵌套。
  • 更新时要判断用户是否上传了新图片——如果没有上传,就不需要执行删除旧图的操作,也不要更新图片相关字段。

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

火山引擎 最新活动