【问题标题】:Upload image to cloud storage from firebase cloud functions从 Firebase 云功能将图像上传到云存储
【发布时间】:2021-10-28 23:49:59
【问题描述】:

我正在努力从云功能上传一张图片 我正在使用 onRequest 将图像从网络发送到云功能。我正在发送一个 base64 字符串和文件名。现在我在互联网上关注不同的教程,似乎无法解决我的问题。

这是我的代码。我认为我在服务帐户 json 上做错了。虽然我生成了 json 文件并使用了它,但它仍然没有工作。

当我不使用服务帐户 json 时,我收到 The caller does not have permission at Gaxios._request 的错误 当我确实使用 serviceAccount.json 时,我会收到此错误 The "path" argument must be of type string. Received an instance of Object,我认为该错误来自 file.createWriteStream()

这里是代码,任何人都可以帮我解决这个问题

我使用的projectId如下图所示

const functions = require("firebase-functions");
const admin = require("firebase-admin");

const projectId = functions.config().apikeys.projectid; // In the picture below

const stream = require("stream");

const cors = require("cors")({ origin: true });

const { Storage } = require("@google-cloud/storage");
//  Enable Storage
const storage = new Storage({
  projectId: projectId, // I did use serviceAccount json here but that wasn't working
});




// With serviceAccount.json code
// const storage = new Storage({
//      projectId: projectId,
//      keyFilename: serviceAccount,
//    });
// This is giving the error of: The "path" argument must be of type string. Received an instance of Object
    
exports.storeUserProfileImage = functions.https.onRequest((req, res) => {
  cors(req, res, async () => {
    try {
      const bucket = storage.bucket(`gs://${projectId}.appspot.com`);

      let pictureURL;
      const image = req.body.image;
      const userId = req.body.userId;
      const fileName = req.body.fileName;

      const mimeType = image.match(
        /data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/
      )[1];
      //trim off the part of the payload that is not part of the base64 string
      const base64EncodedImageString = image.replace(
        /^data:image\/\w+;base64,/,
        ""
      );
      const imageBuffer = Buffer.from(base64EncodedImageString, "base64");
      const bufferStream = new stream.PassThrough();
      bufferStream.end(imageBuffer);
      // Define file and fileName
      const file = bucket.file("images/" + fileName);

      bufferStream
        .pipe(
          file.createWriteStream({
            metadata: {
              contentType: mimeType,
            },
            public: true,
            validation: "md5",
          })
        )
        .on("error", function (err) {
          console.log("error from image upload", err.message);
        })
        .on("finish", function () {
          // The file upload is complete.
          console.log("Image uploaded");
          file
            .getSignedUrl({
              action: "read",
              expires: "03-09-2491",
            })
            .then((signedUrls) => {
              // signedUrls[0] contains the file's public URL
              console.log("Signed urls", signedUrls[0]);
              pictureURL = signedUrls[0];
            });
        });
      console.log("image url", pictureURL);
      res.status(200).send(pictureURL);
    } catch (e) {
      console.log(e);
      return { success: false, error: e };
    }
  });
});

【问题讨论】:

  • 请附上您使用服务帐号的代码。
  • @VictorEronmosele 做到了吗

标签: javascript node.js firebase google-cloud-functions google-cloud-storage


【解决方案1】:
const storage = new Storage({
  projectId: projectId
  keyFilename: "" // <-- Path to a .json, .pem, or .p12 key file
});

keyFilename 接受存储您的服务帐户的路径和凭据本身。

folder
  |-index.js
  |-credentials
    |-serviceAccountKey.json

如果你的目录结构看起来像这样,那么路径应该是这样的:

const storage = new Storage({
  projectId: projectId
  keyFilename: "./credentials/serviceAccountKey.json"
});

请注意,如果您使用云函数,那么 SDK 将使用 Application Default Credentials,因此您不必传递这些参数。简单初始化如下图:

const storage = new Storage()

【讨论】:

  • 我这样做了,但我认为该文件不存在于服务器端。基本上在云端,所以我收到了这个错误。虽然我的本地设置错误来自图像上传 ENOENT: no such file or directory, open '/swmcontactportal-firebase-adminsdk-hl76c-3ad043c522.json
  • @SulmanAzhar 如果使用云功能,您无需传递任何内容(请查看更新的答案)。如果您使用自己的服务器,则必须将服务帐户复制到服务器。
  • 是的,我正在使用云功能,我删除了所有内容,因此它使用默认值,但这仍然无法正常工作。现在收到此错误错误:调用者在 Gaxios._request 没有权限
  • 会不会是因为const bucket = storage.bucket(`gs://${projectId}.appspot.com`);这个代码。我正在使用默认文件夹存储桶的存储选项卡中提供的链接,您可以在这张图片中查看i.imgur.com/5aOHI9R.png
  • @SulmanAzhar 尝试使用storage.bucket("your-bucket-name") 而不是完整的 URL。在这种情况下,它将是 projectId
【解决方案2】:

首先我没有提供任何服务帐户,因为我正在使用 @Dharmaraj 在他的回答中所说的 firebase 云功能 其次,这是google云平台的权限问题,可以通过以下步骤解决

转到您项目的 Cloud Console (https://console.cloud.google.com/) > IAM & admin > IAM,找到 App Engine default service account 然后单击最左侧的铅笔 > 单击添加角色 > 在过滤器字段中输入 Service Account Token Creator 并点击保存就可以了

从这里找到这个解决方案 https://github.com/firebase/functions-samples/issues/782

【讨论】:

    猜你喜欢
    • 2021-04-21
    • 2019-06-23
    • 2017-12-21
    • 2019-08-08
    • 2021-01-12
    • 2021-06-16
    • 2020-07-05
    • 2020-04-25
    • 2018-04-09
    相关资源
    最近更新 更多