从Firebase的云函数上载的文件中获取下载URL

2024-10-02 00:28:01 发布

您现在位置:Python中文网/ 问答频道 /正文

在使用Firebase的函数在Firebase存储中上载一个文件后,我想获取该文件的下载url

我有这个:

...

return bucket
    .upload(fromFilePath, {destination: toFilePath})
    .then((err, file) => {

        // Get the download url of file

    });

对象文件有很多参数。甚至一个名为mediaLink的。但是,如果我尝试访问此链接,则会出现以下错误:

Anonymous users does not have storage.objects.get access to object ...

有人能告诉我如何获取公共下载Url吗

多谢各位


Tags: 文件the函数urlgetreturnbucketdestination
3条回答

下面是一个关于如何在上载时指定下载令牌的示例:

const UUID = require("uuid-v4");

const fbId = "<YOUR APP ID>";
const fbKeyFile = "./YOUR_AUTH_FIlE.json";
const gcs = require('@google-cloud/storage')({keyFilename: fbKeyFile});
const bucket = gcs.bucket(`${fbId}.appspot.com`);

var upload = (localFile, remoteFile) => {

  let uuid = UUID();

  return bucket.upload(localFile, {
        destination: remoteFile,
        uploadType: "media",
        metadata: {
          contentType: 'image/png',
          metadata: {
            firebaseStorageDownloadTokens: uuid
          }
        }
      })
      .then((data) => {

          let file = data[0];

          return Promise.resolve("https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent(file.name) + "?alt=media&token=" + uuid);
      });
}

然后打电话给我

upload(localPath, remotePath).then( downloadURL => {
    console.log(downloadURL);
  });

这里的关键是metadata选项属性中嵌套了一个metadata对象。将firebaseStorageDownloadTokens设置为uuid-v4值将告诉云存储将其用作其公共身份验证令牌

非常感谢@Martemorphosis

此答案将总结将文件上载到Google/Firebase云存储时获取下载URL的选项。有三种类型的下载URL:

  1. 已签名下载URL,这些URL是临时的,具有安全功能
  2. 令牌下载URL,具有持久性和安全特性
  3. 公共下载URL,持久且缺乏安全性

有三种方法可以获取令牌下载URL。其他两个下载URL只有一种方法可以获取它们

从Firebase存储控制台

您可以从Firebase存储控制台获取下载URL:

enter image description here

下载URL如下所示:

https://firebasestorage.googleapis.com/v0/b/languagetwo-cd94d.appspot.com/o/Audio%2FEnglish%2FUnited_States-OED-0%2Fabout.mp3?alt=media&token=489c48b3-23fb-4270-bd85-0a328d2808e5

第一部分是文件的标准路径。最后是代币。此下载URL是永久的,即不会过期,但您可以撤销它

从前端获取下载URL()

documentation告诉我们使用getDownloadURL()

let url = await firebase.storage().ref('Audio/English/United_States-OED-' + i +'/' + $scope.word.word + ".mp3").getDownloadURL();

这与您可以从Firebase存储控制台获得的下载URL相同。这种方法很简单,但需要知道文件的路径,在我的应用程序中,对于一个相对简单的数据库结构,大约需要300行代码。如果您的数据库很复杂,这将是一场噩梦。你可以从前端上传文件,但这会让下载你的应用的任何人暴露你的凭证。因此,对于大多数项目,您都希望从节点后端或谷歌云功能上传文件,然后获取下载URL并将其与文件的其他数据一起保存到数据库中

getSignedUrl()用于临时下载URL

getSignedUrl()易于从节点后端或谷歌云功能使用:

  function oedPromise() {
    return new Promise(function(resolve, reject) {
      http.get(oedAudioURL, function(response) {
        response.pipe(file.createWriteStream(options))
        .on('error', function(error) {
          console.error(error);
          reject(error);
        })
        .on('finish', function() {
          file.getSignedUrl(config, function(err, url) {
            if (err) {
              console.error(err);
              return;
            } else {
              resolve(url);
            }
          });
        });
      });
    });
  }

签名下载URL如下所示:

https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio%2FSpanish%2FLatin_America-Sofia-Female-IBM%2Faqu%C3%AD.mp3?GoogleAccessId=languagetwo-cd94d%40appspot.gserviceaccount.com&Expires=4711305600&Signature=WUmABCZIlUp6eg7dKaBFycuO%2Baz5vOGTl29Je%2BNpselq8JSl7%2BIGG1LnCl0AlrHpxVZLxhk0iiqIejj4Qa6pSMx%2FhuBfZLT2Z%2FQhIzEAoyiZFn8xy%2FrhtymjDcpbDKGZYjmWNONFezMgYekNYHi05EPMoHtiUDsP47xHm3XwW9BcbuW6DaWh2UKrCxERy6cJTJ01H9NK1wCUZSMT0%2BUeNpwTvbRwc4aIqSD3UbXSMQlFMxxWbPvf%2B8Q0nEcaAB1qMKwNhw1ofAxSSaJvUdXeLFNVxsjm2V9HX4Y7OIuWwAxtGedLhgSleOP4ErByvGQCZsoO4nljjF97veil62ilaQ%3D%3D

签名的URL具有过期日期和长签名。命令行gsutil signurl -d的文档说明,签名URL是临时的:默认过期时间为一小时,最大过期时间为七天

我要在这里大声说getSignedUrl从来没有说过你的签名URL将在一周内过期。文档代码将3-17-2025作为过期日期,这表明您可以在将来设置过期年份。我的应用程序工作正常,一周后崩溃了。错误消息说签名不匹配,而不是下载URL已过期。我对我的代码做了各种各样的修改,一切正常……直到一周后全部崩溃。这种情况持续了一个多月的沮丧

公开您的文件

您可以将文件的权限设置为公共读取,如documentation中所述。这可以通过云存储浏览器或节点服务器完成。您可以将一个文件或目录或整个存储数据库公开。以下是节点代码:

var webmPromise = new Promise(function(resolve, reject) {
      var options = {
        destination: ('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3'),
        predefinedAcl: 'publicRead',
        contentType: 'audio/' + audioType,
      };

      synthesizeParams.accept = 'audio/webm';
      var file = bucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm');
      textToSpeech.synthesize(synthesizeParams)
      .then(function(audio) {
        audio.pipe(file.createWriteStream(options));
      })
      .then(function() {
        console.log("webm audio file written.");
        resolve();
      })
      .catch(error => console.error(error));
    });

在云存储浏览器中,结果如下所示:

enter image description here

然后,任何人都可以使用标准路径下载您的文件:

https://storage.googleapis.com/languagetwo-cd94d.appspot.com/Audio/English/United_States-OED-0/system.mp3

另一种公开文件的方法是使用方法makePublic()。我还没能让它正常工作,要使bucket和文件路径正确是很困难的

一个有趣的替代方法是使用Access Control Lists。您可以使文件仅对您在列表中列出的用户可用,或者使用authenticatedRead使从Google帐户登录的任何人都可以使用该文件。如果有一个选项“任何使用Firebase Auth登录我的应用程序的人”,我会使用这个选项,因为它将仅限制我的用户访问

使用firebaseStorageDownloadTokens构建您自己的下载URL

有几个答案描述了一个未记录的Google存储对象属性firebaseStorageDownloadTokens。有了它,您可以告诉存储您想要使用的令牌。您可以使用uuid节点模块生成令牌。四行代码,您可以构建自己的下载URL,相同的dow从控制台或getDownloadURL()获取的nload URL。这四行代码是:

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
metadata: { firebaseStorageDownloadTokens: uuid }
https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm') + "?alt=media&token=" + uuid);

以下是上下文中的代码:

var webmPromise = new Promise(function(resolve, reject) {
  var options = {
    destination: ('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.mp3'),
    contentType: 'audio/' + audioType,
    metadata: {
      metadata: {
        firebaseStorageDownloadTokens: uuid,
      }
    }
  };

      synthesizeParams.accept = 'audio/webm';
      var file = bucket.file('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm');
      textToSpeech.synthesize(synthesizeParams)
      .then(function(audio) {
        audio.pipe(file.createWriteStream(options));
      })
      .then(function() {
        resolve("https://firebasestorage.googleapis.com/v0/b/" + bucket.name + "/o/" + encodeURIComponent('Audio/' + longLanguage + '/' + pronunciation + '/' + word + '.webm') + "?alt=media&token=" + uuid);
      })
      .catch(error => console.error(error));
});

这不是打字错误--你必须把firebaseStorageDownloadTokens嵌套在双层metadata:

Doug Stevenson指出firebaseStorageDownloadTokens不是Google官方的云存储功能。你在谷歌的任何文档中都找不到它,也不能保证它会出现在未来版本的@google-cloud。我喜欢firebaseStorageDownloadTokens,因为这是唯一能得到我想要的东西的方法,但它有一种“气味”,使用起来不安全

为什么没有来自节点的getDownloadURL()?

正如@Clinton所写,谷歌应该在@google-cloud/storage(即,您的节点后端)中创建一个file.getDownloadURL()a方法。我想从谷歌云功能上传一个文件,并获得令牌下载URL

您需要通过@google-cloud/storageNPM模块使用getSignedURL生成一个签名URL

例如:

const gcs = require('@google-cloud/storage')({keyFilename: 'service-account.json'});
// ...
const bucket = gcs.bucket(bucket);
const file = bucket.file(fileName);
return file.getSignedUrl({
  action: 'read',
  expires: '03-09-2491'
}).then(signedUrls => {
  // signedUrls[0] contains the file's public URL
});

您需要使用your service account credentials初始化@google-cloud/storage,因为应用程序默认凭据不足

更新:现在可以通过Firebase管理SDK访问云存储SDK,该SDK位于@google Cloud/Storage附近。唯一的方法是,如果您:

  1. 使用特殊服务帐户初始化SDK,通常通过第二个非默认实例
  2. 或者,在没有服务帐户的情况下,为默认的应用程序引擎服务帐户授予“signBlob”权限

相关问题 更多 >

    热门问题