【问题标题】:How can I delete images from Cloudinary using multer-storage-cloudinary package?如何使用 multer-storage-cloudinary 包从 Cloudinary 中删除图像?
【发布时间】:2020-12-18 13:19:44
【问题描述】:

我可以使用 multer-storage-cloudinary 包成功上传图像,但我还没有拼凑出如何从我的更新或删除路由中销毁 cloudinary 中的图像的实现。我发现的所有资源仅参考上传图片。这是我必须上传的图片

const cloudinary = require('cloudinary').v2;
const { CloudinaryStorage } = require('multer-storage-cloudinary');
const multer = require('multer');

cloudinary.config({
  cloud_name: process.env.CLOUD_NAME,
  api_key: process.env.API_KEY,
  api_secret: process.env.API_SECRET
});

const storage = new CloudinaryStorage({
  cloudinary: cloudinary,
  params: {
    folder: "works",
    allowedFormats: ["jpg", "png"]
  }
});
const imgUpload = multer({ storage: storage });

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,
        user_id     : req.session.user_id
    })
        .then((dbPostData) => res.json(dbPostData))
        .catch((err) => {
            console.log(err);
            res.status(500).json(err);
        });
});

这是处理表单提交的前端代码

async function newFormHandler(event) {
    event.preventDefault();

    const form = document.querySelector('#new-post-form');

    const formData = new FormData(form);

    const response = await fetch(`/api/posts`, {
        method : 'POST',
        body   : formData
    });

    if (response.ok) {
        document.location.replace('/dashboard');
    } else {
        alert(response.statusText);
    }
}

document.querySelector('#new-post-form').addEventListener('submit', newFormHandler);

最后是我的更新路线,用于上传新图像并将其保存到数据库的新路径,但我也想从 Cloudinary 中删除旧图像,这样我就不会在那里建立未使用的工件。

router.put('/:id', withAuth, imgUpload.single('work-img'), (req, res) => {
    Post.update(
        {
            title       : req.body.title,
            dimension   : req.body.dimensions,
            description : req.body.description,
            media       : req.body.media,
            img_url     : req.file.path
        },
        {
            where : {
                id : req.params.id
            }
        }
    )
        .then((dbPostData) => {
            if (!dbPostData) {
                res.status(404).json({ message: 'No post found with this id' });
                return;
            }
            res.json(dbPostData);
        })
        .catch((err) => {
      console.log(err);
            res.status(500).json(err);
        });
});

如果我在 post 路由中查看 console.log(req.file),它会给我类似的东西

{
  fieldname: 'work-img',
  originalname: '20171005_134508.jpg',
  encoding: '7bit',
  mimetype: 'image/jpeg',
  path: 'https://res.cloudinary.com/xxxxxxxxx/image/upload/xxxxxxxx/works/ujrrf13kyil8l5rjccwf.jpg',
  size: 3647252,
  filename: 'works/ujrrf13kyil8l5rjccwf'
}
根据 Cloudinary API 文档,响应看起来与“public_id”等键有很大不同。

{
  "public_id": "eneivicys42bq5f2jpn2",
  "version": 1570979139,
  "signature": "abcdefghijklmnopqrstuvwxyz12345",
  "width": 1000,
  "height": 672,
  "format": "jpg",
  "resource_type": "image",
  "created_at": "2017-08-11T12:24:32Z",
  "tags": [],
  "bytes": 350749,
  "type": "upload",
  "etag": "5297bd123ad4ddad723483c176e35f6e",
  "url": "http://res.cloudinary.com/demo/image/upload/v1570979139/eneivicys42bq5f2jpn2.jpg",
  "secure_url": "https://res.cloudinary.com/demo/image/upload/v1570979139/eneivicys42bq5f2jpn2.jpg",
  "original_filename": "sample",
  "eager": [
    { "transformation": "c_pad,h_300,w_400",
      "width": 400,
      "height": 300,
      "url": "http://res.cloudinary.com/demo/image/upload/c_pad,h_300,w_400/v1570979139/eneivicys42bq5f2jpn2.jpg",
      "secure_url": "https://res.cloudinary.com/demo/image/upload/c_pad,h_300,w_400/v1570979139/eneivicys42bq5f2jpn2.jpg" },

然后我可以像这样将'public_id'与destroy方法一起使用,但我无权访问public_id来配置它:cloudinary.v2.uploader.destroy(public_id, options, callback);

我不清楚如何实现这一点,或者是否可以使用 multer-storage-cloudinary 包

【问题讨论】:

    标签: node.js express multer cloudinary


    【解决方案1】:

    所以对于任何可能对我最终这样做的方式感兴趣的人如下

    router.put('/:id', withAuth, imgUpload.single('work-img'), (req, res) => {
        // if there was a picture updated -- NOTE THIS TECHNIQUE IS NOT DRY, IS THERE A WAY TO REFACTOR?
        if (req.file) {
            // find old public_id for image so we can delete it from cloudinary before updating the db with new path
            Post.findOne(
                {
                    where : {
                        id : req.params.id
                    }
                },
                {
                    attributes : [ 'title', 'public_id' ]
                }
            )
                .then((oldPostData) => {
                    const oldPublicId = oldPostData.get({ plain: true });
    
                    // remove old image from cloudinary db
                    cloudinary.uploader.destroy(oldPublicId.public_id, (err) => {
                        console.log(err);
                        console.log(oldPublicId, ' deleted');
                    });
    
                    // not in cloudinary callback since deletion from cloudinary is not critical to UX
                    Post.update(
                        {
                            title       : req.body.title,
                            artist_name : req.body.artist,
                            dimension   : req.body.dimensions,
                            description : req.body.description,
                            media       : req.body.media,
                            img_url     : req.file.path,
                            public_id   : req.file.filename
                        },
                        {
                            where : {
                                id : req.params.id
                            }
                        }
                    ).then((newPostData) => {
                        if (!newPostData) {
                            res.status(404).json({ message: 'No post found with this id' });
                            return;
                        }
    
                        req.flash('success', 'Your work has been updated!');
                        res.json(newPostData);
                    });
                })
                .catch((err) => {
                    console.log(err);
                    res.status(500).json(err);
                });
        // in the else i just added the post to the db without the image file.
        } else {...}

    如上所述,public_id 是您用来访问 cloudinary 中的图像的。因此 multer-storage-cloudinary 中间件负责从表单中获取图像并将其直接上传到 cloudinary 然后将来自 cloudinary 的响应打包到 req.file 中,multer 通常将其添加到 req 对象中。 (显然模式需要使用新的 public_id 字段进行更新)。在 PUT 回调中,查询数据库中的帖子并获取旧的 public_id。解析它并将其传递给 cloudinay.uploader.destroy() 方法。如果您的路线与您的 imgUpload 配置位于单独的文件中,则您需要使用 cloudinary。那么您可以从 cloudinary 回调内部更新您的数据库,也可以不更新,因为它们不相互依赖,而且 cloudinary 操作对用户体验并不重要。

    【讨论】:

    【解决方案2】:

    对于删除,public_id 是必需的。如果您在使用 multer-storage-cloudinary 时没有在响应中获得 public_id,您可以在上传时将其作为参数传递,这将是 Cloudinary 上图像的名称。要删除图像,您只需使用该 public_id。或者,您可以使用 cloudinary.uploader.upload 函数,该函数将返回 JSON 以及您在示例响应中提到的 public_id 和其他详细信息。

    【讨论】:

    • multer-storage-cloudinary 公开了一个文件名属性,即 public_id。它有点像这样,但只有在最近发布的情况下才会删除 cloudinary 上的正确图像。 router.put('/:id', withAuth, imgUpload.single('work-img'), (req, res) => { cloudinary.uploader.destroy(req.session.public_id, () => { req. session.public_id = req.file.filename; Post.update( ... public_id : req.file.filename ) ... 关于如何从 put 回调内部访问 req.file.filename 的先前值而不是的任何建议会话?
    【解决方案3】:
    import { v2 as cloudinary } from "cloudinary";
    import express from "express";
    const router = express.Router();
    
    router.route("/delete-image").post(async (req, res, next) => {
        try {
            cloudinary.uploader.destroy(req.body.public_id, function (error, result) {
                res.status(200).send({ result, error });
            });
        } catch (error) {
            next(error);
        }
        // public_id: "folder_name/file_name" WITHOUT file extension
    });
    
    export default router;
    

    我就是这样做的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-05
      • 2020-03-02
      • 2020-11-05
      • 2019-05-25
      • 2015-08-11
      • 2018-05-24
      • 2019-01-30
      • 2021-11-12
      相关资源
      最近更新 更多