如何通过可调用的https云功能将文件上传到Firebase存储中

我一直在尝试使用可调用的Firebase云功能将文件上传到 Firebase存储。 我要做的就是使用axios从URL提取图像并尝试上传到存储。 我面临的问题是,我不知道如何保存来自axios的响应并将其上传到存储。

首先,如何将接收到的文件保存在os.tmpdir()创建的temp目录中。 然后如何将其上传到存储。 在这里,我以arraybuffer的形式接收数据,然后将其转换为Blob并尝试上传。 这是我的代码。我一直想念一个主要部分。 如果有更好的方法,请推荐我。我一直在浏览大量文档,但没有找到明确的解决方案。请指导。预先感谢。


const bucket = admin.storage().bucket();
const path = require('path');
const os = require('os');
const fs = require('fs');
module.exports = functions.https.onCall((data,context) => {
  try {
    return new Promise((resolve,reject) => {
      const {
        imageFiles,companyPIN,projectId
      } = data;
      const filename = imageFiles[0].replace(/^.*[\\\/]/,'');
      const filePath = `ProjectPlans/${companyPIN}/${projectId}/images/${filename}`; // Path i am trying to upload in FIrebase storage
      const tempFilePath = path.join(os.tmpdir(),filename);
      const metadata = {
        contentType: 'application/image'
      };
      axios
        .get(imageFiles[0],{ // URL for the image
          responseType: 'arraybuffer',headers: {
            accept: 'application/image'
          }
        })
        .then(response => {
          console.log(response);
          const blobObj = new Blob([response.data],{
            type: 'application/image'
          });
          return blobObj;
        })
        .then(async blobObj => {
          return bucket.upload(blobObj,{
            destination: tempFilePath    // Here i am wrong.. How to set the path of downloaded blob file
          });
        }).then(buffer => {
          resolve({ result: 'success' });
        })
        .catch(ex => {
          console.error(ex);
        });
    });
  } catch (error) {
    // unknown: 500 Internal Server Error
    throw new functions.https.HttpsError('unknown','Unknown error occurred. Contact the administrator.');
  }
});

tongfang001 回答:如何通过可调用的https云功能将文件上传到Firebase存储中

我会采取略有不同的方法,并且完全避免使用本地文件系统,因为它只是tmpfs,并且会浪费您的内存,无论您使用什么函数来保持缓冲区/ blob,因此避免它和使用它更简单。使用GCS文件对象上的save method从该缓冲区直接写入GCS。

这是一个例子。我简化了许多设置,并且使用的是http函数而不是可调用函数。同样,我使用的是公共stackoverflow图片,而不是您的原始网址。无论如何,您都应该能够使用此模板将其修改回所需的内容(例如,更改原型并删除http响应,然后将其替换为所需的返回值):

const functions = require('firebase-functions');
const axios = require('axios');
const admin = require('firebase-admin');
admin.initializeApp();

exports.doIt = functions.https.onRequest((request,response) => {
    const bucket = admin.storage().bucket();
    const IMAGE_URL = 'https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.svg';
    const MIME_TYPE = 'image/svg+xml';
    return axios.get(IMAGE_URL,{ // URL for the image
        responseType: 'arraybuffer',headers: {
          accept: MIME_TYPE
        }
      }).then(response => {
        console.log(response);  // only to show we got the data for debugging
        const destinationFile = bucket.file('my-stackoverflow-logo.svg');  
        return destinationFile.save(response.data).then(() => {  // note: defaults to resumable upload
          return destinationFile.setMetadata({ contentType: MIME_TYPE });
        });
      }).then(() => { response.send('ok'); })
      .catch((err) => { console.log(err); })
  });

正如评论者所述,在上面的示例中,axios请求本身可以进行外部网络访问,因此您需要处于Blaze或Flame计划。但是,这似乎并不是您当前遇到的问题。

同样,默认情况下,这也默认使用可恢复的上载,当您处理大量小文件(the documentation不建议这样做,因为这样做会产生一些开销。


您询问如何将其用于下载多个文件。这是一种方法。首先,假设您有一个函数返回给定的文件名,该文件将根据文件名下载一个文件(我从上面已对此进行了删节,但除了将INPUT_URL更改为filename以外,其基本相同- -请注意,它不会返回诸如response.send()之类的最终结果,并且隐式地假设所有文件都是相同的MIME_TYPE):

function downloadOneFile(filename) {
  const bucket = admin.storage().bucket();
  const MIME_TYPE = 'image/svg+xml';
  return axios.get(filename,...)
    .then(response => {
       const destinationFile = ...
     });
}

然后,您只需要从文件列表中迭代构建一个Promise链。可以说它们在imageUrls中。构建完成后,返回整个链:

let finalPromise = Promise.resolve();
imageUrls.forEach((item) => { finalPromise = finalPromise.then(() => downloadOneFile(item)); });

// if needed,add a final .then() section for the actual function result

return finalPromise.catch((err) => { console.log(err) });

请注意,您还可以构建一个promise数组并将其传递给Promise.all(),这可能会更快一些,因为您将获得一些并行性,但是除非您非常确定所有这些,否则我不建议您这样做的数据将立即放入函数的内存中。即使采用这种方法,您也需要确保所有下载都可以在函数的超时时间内完成。

本文链接:https://www.f2er.com/3165784.html

大家都在问