【问题标题】:Best way to store images in MERN stack web application在 MERN 堆栈 Web 应用程序中存储图像的最佳方式
【发布时间】:2020-10-02 20:37:58
【问题描述】:

我正在使用 MERN 堆栈(MongoDB、Express Server、ReactJS 前端和 NodeJS 后端)构建一个 Web 应用程序,并且想知道一些从后端存储图像的好方法。

过去,我直接从前端使用 Firebase 进行身份验证和存储。当我在 MongoDB 中处理我自己的用户身份验证模型时,是否仍然可以使用 firebase 存储,如果可以,它会来自前端还是后端。如果它来自前端,我如何在没有 Firebase 身份验证的情况下保护它?

我读过的其他选项是使用 GridFS 将图像存储到 MongoDB 或使用 Multer 存储在服务器上。

一旦我想到了一个解决方案,我就可以阅读文档并弄清楚如何完成它。

感谢任何建议。

【问题讨论】:

    标签: node.js reactjs mongodb firebase mern


    【解决方案1】:

    您可以通过[实现自定义提供程序](后者为https://firebase.google.com/docs/auth/web/custom-auth)将任何外部身份验证系统连接到 Firebase 身份验证。

    这要求您在受信任的环境中运行代码,例如您控制的服务器或 Cloud Functions,您可以在其中获取用户的身份验证结果并将其转换为 Firebase 身份验证令牌。

    然后,客户端使用该令牌登录 Firebase,从那一刻起,存储(和其他服务)就像以前一样了解用户。

    【讨论】:

      【解决方案2】:

      一个选项是将图像上传到客户端的Cloudinary,然后使用您自己的 API 将返回的 URL 保存到 MongoDB。 Cloudinary 不仅可以托管您的图像,还可以处理图像操作和优化等等。

      基本上你要做的是:

      1. 注册 Cloudinary 帐户
      2. 进入设置 -> 上传
      3. 使用“未签名模式”添加“上传预设”以启用未签名上传到 Cloudinary

      那么你的上传功能可以是这样的:

      async function uploadImage(file) { // file from <input type="file"> 
        const data = new FormData();
        data.append("file", file);
        data.append("upload_preset", NAME_OF_UPLOAD_PRESET);
      
        const res = await fetch(
          `https://api.cloudinary.com/v1_1/${YOUR_ID}/image/upload`,
          {
            method: "POST",
            body: data,
          }
        );
        const img = await res.json();
        // Post `img.secure_url` to your server and save to MongoDB
      }
      

      【讨论】:

      • 嘿@Hangindev,这正是我想做的,但我仍然是超级新的 MERN 和 Cloudinary。你介意帮我解决这个问题吗?我只是不能 100% 确定一切都应该去哪里jsfiddle.net/qfme5h8k
      • 嗨@FrazerFindlater,你可以看看我整理的这个codesandbox
      【解决方案3】:

      我认为使用 multer 是非常方便的方法。

      您可以使用 multer 将图像上传到文件夹并将参考 URL 存储在 MongoDB 中。如果您愿意托管您的 MERN 应用程序,这一点也很重要。您不需要任何第三方帮助,例如 firebase 或 Cloudinary 上传和身份验证(您已经这样做了)。

      因此,您可以使用自己的功能来托管自己的应用。没有外部成本(仅针对域:D)

      这可以帮助您获得一个简短的想法。

      const InstrumentImageStore = multer.diskStorage({
        destination: function (req, file, callback) {
          const userId = req.userId;
          const dir = `instrumentImgs/${userId}`;
          fs.exists(dir, (exist) => {
            if (!exist) {
              return fs.mkdir(dir, (error) => callback(error, dir));
            }
            return callback(null, dir);
          });
      
        },
        filename: function (req, file, callback) {
          callback(null, Date.now() + "-" + file.originalname);
        },
      });
      
      router.post(
        "/add/instrument",
        [isauth, multer({ storage: InstrumentImageStore }).array("imageArr", 5)],
      //isauth is another middleware that restricts requests using JWT
        instrumentController.addInstrument
      );
      

      【讨论】:

        【解决方案4】:

        我最终从 Firebase Admin SDK 实现了 Firebase 存储,并使用 Multer 将图像存储在内存中,直到我将它们加载到 Firebase。

        https://firebase.google.com/docs/storage/admin/start

        const uploader = multer({
          storage: multer.memoryStorage(),
          limits: {
            fileSize: 5 * 1024 * 1024,
          },
        });
        
        
        // @route   POST api/users/upload/avatar
        // @desc    Upload a new avatar and save to storage
        // @access  Private
        router.post('/upload/avatar', [auth, uploader.single('image')], async (req, res, next) => {
          if (!req.file) {
            res.status(400).json({ msg: 'No file submitted.' });
            return;
          }
        
          try {
            const blob = firebase.bucket.file(req.file.originalname);
            const blobStream = blob.createWriteStream({
              gzip: true,
              resumable: false,
              metadata: {
                contentType: req.file.mimetype,
              },
            });
        
            blobStream.on('error', (err) => next(err));
        
            blobStream.on('finish', () => {
              publicUrl = `https://firebasestorage.googleapis.com/v0/b/${
                firebase.bucket.name
              }/o/${encodeURI(blob.name)}?alt=media`;
        
              res.status(200).json({
                photoURL: publicUrl,
              });
        
              User.findById(req.user.id).then((user) => {
                user.photoURL = publicUrl;
                user.save();
              });
            });
        
            blobStream.end(req.file.buffer);
          } catch (error) {
            console.error(error.message);
            res.status(500).send({ msg: 'A Server error occurred' });
          }
        });
        

        认为如果将来有人偶然发现这篇文章,这可能会有所帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-12
          • 2020-01-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-29
          相关资源
          最近更新 更多