【问题标题】:Unable to upload image to firebase storage with firebase functions无法使用 firebase 功能将图像上传到 firebase 存储
【发布时间】:2020-03-05 04:58:29
【问题描述】:

这是我的代码:-

exports.uploadImage = (req, res) => {

    const BusBoy = require('busboy');
    const path = require('path');
    const os = require('os');
    const fs = require('fs');

    const busboy = new BusBoy({ headers: req.headers });

    let imageFileName;
    let imageToBeUploaded = {};

    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {

        const imageExtension = filename.split('.')[filename.split('.').length - 1];
        imageFileName = `${Math.round(Math.random() * 100000000000)}.${imageExtension}`;
        const filepath = path.join(os.tmpdir(), imageFileName);
        imageToBeUploaded = { filepath, mimetype };
        file.pipe(fs.createWriteStream(filepath));

    });

    busboy.on('finish', () => {

        console.log('Busboy on started');    

        //code breaks here    
        admin.storage().bucket().upload(imageToBeUploaded.filepath, {
            resumable: false,
            metadata: {
                metadata: {
                    contentType: imageToBeUploaded.mimetype
                }
            }
        })
        .then(() => {
            const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}?alt=media`;
            console.log('logging image url' + imageUrl);
            return db.doc(`/users/${req.user.handle}`).update({ imageUrl })
        })
        .then(() => {
            return res.json({ message: 'Image uploaded successfully' });
        })
        .catch(err => {
            console.error(err);
            return res.status(500).json({ error: err.code });
        })
    });
    busboy.end(req.rawBody);
}

我在评论中提到了我的代码在哪里中断,我得到的错误是Error: Cannot parse response as JSON: Not Found message: 'Cannot parse response as JSON: Not Found'

错误消息显示无法将响应解析为JSON。这是否意味着来自 firebase 的响应不是 JSON?我在请求的标头中有一个令牌,在正文中有一个图像作为表单数据。我真的不知道哪里出了问题,请帮忙

【问题讨论】:

  • 你有没有试过把它变成一个minimal, complete, reproducible example(例如,一个只查看存储调用的单独的?特别是因为你混合了firebase风格(例如使用管理API)和非 firebase 风格(您的云函数声明),有一些完整的东西可以重现会很有帮助。
  • 另一个观察结果——与其将输入文件通过管道传输到文件系统,然后通过upload() 将其读回,不如使用 GCS createWriteStream API 并直接通过管道传输。跨度>
  • @robsiemb 实际上我正在关注一个在线教程,代码来自该教程,所以我不知道我遵循什么风格
  • @robsiemb 你能说出你的意思是什么吗?
  • 管道:调用file.pipe() 写入流。当您可以直接写入通过createWriteStream api 进入 GCS 的流时,没有理由写入文件系统然后从文件系统读回。

标签: firebase google-cloud-firestore google-cloud-functions google-cloud-storage firebase-storage


【解决方案1】:

在我的情况下,存储桶 ID 配置错误 - 更正后我能够上传文件

【讨论】:

    【解决方案2】:

    很遗憾,我无法识别 JSON 解析错误,因此我改写了代码,使其更加精简,因为 @robsiemb 没有解决。

    您的uploadImage 函数似乎被配置为一些中间件,所以我在下面做了同样的事情。此代码将使用从Reference.push().key 生成的唯一文件名将上传的数据直接流式传输到 Cloud Storage,以防止冲突。

    在下面的代码中,

    • 上传的文件将存储在类似的位置:userData/someUserId/images/-JhLeOlGIEjaIOFHR0xd.png
    • 图像的原始 URL 不会存储在数据库中,因为除非文件对象或包含的存储桶被公开,否则它将需要一个 signed URL,它最多只能持续 7 天(见下文)。
    • 可以接受和上传多个文件。如果不希望这样做,请配置 limits for the BusBoy instance
    • 添加了对非 POST 请求和丢失文件条目的基本错误处理。
    // import Firebase libraries & initialize
    const admin = require('firebase-admin');
    admin.initializeApp(); // initializes from environment variables
    
    // import required modules
    const BusBoy = require('busboy');
    
    exports.uploadImage = (req, res) => {
        if (req.method !== 'POST') {
          res.sendStatus(405); // 405 METHOD_NOT_ALLOWED
          return;
        }
    
        let busboy = new BusBoy({headers: req.headers}); // add {limits: {files: 1}} to limit to only a single file upload
        let bucket = admin.storage().bucket();
        let db = admin.firestore();
    
        let storageFilepath;
        let storageFile;
    
        // Note: Currently only the last file is saved to `/users/${req.user.handle}`
        busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
            let fileext = filename.match(/\.[0-9a-z]+$/i)[0];
    
            storageFilepath = `userData/${req.user.handle}/images/` + getUniqueName() + fileext;
            storageFile = bucket.file(storageFilepath);
    
            file.pipe(storageFile.createWriteStream({ gzip: true }));
        })
        .on('finish', () => {
          if (!storageFile) {
            res.status(400).json({error: 'expected file'}); // 400 BAD_REQUEST
            return;
          }
    
          db.doc(`/users/${req.user.handle}`).update({ imagePath: storageFilepath })
            .then(() => {
                res.status(201).json({ message: 'Image uploaded successfully' }); // 201 CREATED
            })
            .catch((err) => {
              console.error(err);
              res.status(500).json({ error: err.code }); // 500 INTERNAL_SERVER_ERROR
            });
        })
        .on('error', (err) => {
          console.error(err);
          res.status(500).json({ error: err.code });
        });
    
        req.pipe(busboy);
    });
    
    function getUniqueName() {
      // push() without arguments returns a ThennableReference, which we'll abuse for it's key generation
      return admin.database().ref().push().key;
    }
    

    如果您确实希望上传的图片可以公开访问,您可以使用添加到 File.makePublic() 函数中的以下 .on('finish', ...) 处理程序:

    .on('finish', () => {
      if (!storageFile) {
        res.status(400).json({error: 'expected file'}); // 400 BAD_REQUEST
        return;
      }
    
      storageFile.makePublic()
        .then(() => {
          return db.doc(`/users/${req.user.handle}`).update({
              imagePath: storageFilepath,
              imageUrl: `https://storage.googleapis.com/${config.storageBucket}/${storageFilepath}`
            });
        })
        .then(() => {
            res.status(201).json({ message: 'Image uploaded successfully' }); // 201 CREATED
        })
        .catch((err) => {
          console.error(err);
          res.status(500).json({ error: err.code }); // 500 INTERNAL_SERVER_ERROR
        });
    })
    

    【讨论】:

      【解决方案3】:

      找到解决问题的办法!

      基本上 - 您需要设置您的 Google 应用程序凭据。进入firebase并查看您的设置。您需要设置环境变量 GOOGLE_APPLICATION_CREDENTIALS 以便 firebase 在您访问这些文件时拥有您的凭据。

      https://firebase.google.com/docs/admin/setup?authuser=1 了解更多信息。

      完成后,检查 Firebase 中的安全设置,在您处理的每个区域。这应该可以解决问题(这绝对是安全问题,而不是您的代码)。

      对于那些正在寻找的人来说,这也是有问题的教程。 https://www.youtube.com/watch?v=m_u6P5k0vP0&t=7661s.

      【讨论】:

        猜你喜欢
        • 2021-04-21
        • 1970-01-01
        • 2019-06-23
        • 2021-10-28
        • 2021-09-18
        • 2020-07-10
        • 2021-07-28
        • 2017-09-25
        相关资源
        最近更新 更多