从使用Cloud Functions for Firebase上传的文件中获取下载URL


124

在将文件上传到具有Firebase功能的Firebase存储中后,我想获取文件的下载URL。

我有这个 :

...

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

        // Get the download url of file

    });

目标文件有很多参数。甚至有一个叫mediaLink。但是,如果尝试访问此链接,则会出现此错误:

匿名用户没有storage.objects.get对对象的访问权限...

有人可以告诉我如何获取公共下载网址吗?

谢谢


另请参阅这篇文章该文章根据功能中可用的数据重建URL。
加藤

Answers:


133

您需要通过@ google-cloud / storage NPM模块使用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
});

您需要@google-cloud/storage使用服务帐户凭据进行初始化,因为应用程序默认凭据不足。

更新:现在可以通过Firebase Admin SDK访问Cloud Storage SDK,该软件充当 @ google-cloud / storage 的包装。唯一的方法是:

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

74
这很奇怪。使用Firebase Android,iOS和Web SDK时,我们可以轻松地从存储参考中获取下载网址。为什么在管理员时不那么容易?PS:在哪里可以找到初始化gcs所需的“ service-account.json”?
瓦伦丁

2
这是因为admin-sdk没有添加任何Cloud Storage。您可以在此处console.firebase.google.com/project/_/settings/serviceaccounts/…中
James Daniels

18
用这种方法生成的URL太长了。通过@martemorfosis提出的方法生成的URL要好得多。是否有产生该URL的函数?这就是我保存在数据库中以供将来使用firebase-sdk时使用的内容。在功能域中必须存在一个镜像方法。
Bogac '17

3
我们如何沿已部署的函数上传service-account.json?我尝试将其放置在functions文件夹中,并在package.json的file字段中引用它,但尚未部署。谢谢。
David Aroesti '17

2
是否需要添加actionexpires
乍得宾厄姆

82

这是有关如何在上传时指定下载令牌的示例:

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);
  });

关键是这里有一个 metadatametadataoption属性中嵌套了对象。设置firebaseStorageDownloadTokens为uuid-v4值将告诉Cloud Storage将其用作其公共身份验证令牌。

非常感谢@martemorfosis


如何为已经上传到存储的文件获取有效的UUID令牌?生成随机UUID没有帮助。有指针吗?
DerFaizio

3
在@martemorfosis帖子中找到了答案。可以从object.metadataexports.uploadProfilePic = functions.storage.object()。onChange(event => {const object = event.data; //存储对象。//存储对象。 // ...
DerFaizio

谢谢你的斗的例子!我尝试了将近1个小时的存储桶和文件方法不同的组合:)
JCarlosR

1
感谢您的回答!就我而言,我正在使用bucket.file(fileName).createWriteStream进行上传,该操作在完成上传后不会返回数据,因此,我使用了encodeURIComponent(fileName)而不是encodeURIComponent(file.name)。
Stanislau Buzunko

2
这应该是正确的答案。它产生的URL与Firebase SDK(@DevMike)生成的URL相似,我敢打赌它的确切作用是在后台进行的。
塞缪尔E.19年

64

此答案将总结在将文件上传到Google / Firebase Cloud Storage时获取下载URL的选项。共有三种下载URL:

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

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

从Firebase存储控制台

您可以从Firebase存储控制台获取下载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是永久性的,即,即使您可以撤消它,它也不会过期。

getDownloadURL()从前端

文档告诉我们使用getDownloadURL()

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

这将获得与您从Firebase Storage控制台获得的下载URL相同的下载URL。这种方法很简单,但是要求您知道文件的路径,在我的应用中,该路径为300行代码,以实现相对简单的数据库结构。如果您的数据库很复杂,那将是一场噩梦。您可以从前端上传文件,但这会将您的凭据公开给下载您的应用程序的任何人。因此,对于大多数项目,您需要从Node后端或Google Cloud Functions上传文件,然后获取下载URL并将其与有关文件的其他数据一起保存到数据库中。

临时下载URL的getSignedUrl()

从节点后端或Google Cloud Functions易于使用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过期。我对代码进行了各种更改,一切正常……直到一个星期后所有崩溃。持续了一个多月的挫败感。

使文件公开可用

您可以将文件的权限设置为公开读取,如文档所述。可以从Cloud Storage Browser或从您的Node服务器完成。您可以将一个文件或目录或整个存储数据库公开。这是节点代码:

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));
    });

结果将在您的Cloud Storage Browser中如下所示:

在此处输入图片说明

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

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

公开文件的另一种方法是使用方法makePublic()。我一直无法解决这个问题,正确设置存储桶和文件路径非常棘手。

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

使用firebaseStorageDownloadTokens构建自己的下载URL

有几个答案描述了一个未记录的Google Storage对象属性firebaseStorageDownloadTokens。这样,您可以告诉Storage您想要使用的令牌。您可以使用uuidNode模块生成令牌。四行代码,您可以构建自己的下载URL,即从控制台或获得的下载URL getDownloadURL()。四行代码是:

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));
});

这不是打字错误-您必须嵌套firebaseStorageDownloadTokensmetadata:

道格·史蒂文森(Doug Stevenson)指出,这firebaseStorageDownloadTokens不是Google Cloud Storage的正式功能。您不会在任何Google文档中找到它,也无法保证它将在的未来版本中使用@google-cloud。我喜欢,firebaseStorageDownloadTokens因为这是获得我想要的东西的唯一方法,但是它有“气味”,使用起来不安全。

为什么不从Node获得getDownloadURL()?

正如@Clinton所写,Google应该在其中创建file.getDownloadURL()一个方法@google-cloud/storage(即,您的Node后端)。我想从Google Cloud Functions上传文件并获取令牌下载URL。


10
我创建了一个问题,@google-cloud/storage对于这一点,随意+1它;)github.com/googleapis/nodejs-storage/issues/697
西奥冠军

1
最新的makePublic()链接。
galki

1
似乎firebaseStorageDownloadTokens不再起作用了。
梅森

1
接受的答案表明,不可能获得不过期的不正确的持久下载URL。您的答案中的细节非常好,应标记为正确答案。谢谢。
DevMike

2
@thomas感谢您的出色总结!您提到了三种获取永久性令牌下载URL的方法,但仅共享2种方法:(a)从Firebase存储控制台,和(b)从前端获取DownloadURL()。我不知道第三种方法是什么?
czphilip

23

通过对函数对象响应的最新更改,您可以获取将“缝合”在一起的所有信息,例如:

 const img_url = 'https://firebasestorage.googleapis.com/v0/b/[YOUR BUCKET]/o/'
+ encodeURIComponent(object.name)
+ '?alt=media&token='
+ object.metadata.firebaseStorageDownloadTokens;

console.log('URL',img_url);

2
您是指对象的响应bucket.file().upload()吗?我在响应数据中没有收到任何元数据属性,并且不确定如何获取这些属性firebaseStorageDownloadTokens
Dygerati

也[你的水桶]时bucket.name,你不必硬编码或使用一个额外的局部变量
克林Darie

4
该解决方案的问题在于服务URL是硬编码的。如果Firebase / Google对其进行更改,则可能会损坏。使用该metadata.mediaLink属性可防止出现此类问题。
洛朗

2
建立这样的网址不受支持。它可能在今天工作,但将来可能会失败。您只应使用提供的API生成正确的下载URL。
道格·史蒂文森

1
依靠可能会更改的硬编码URL是一个错误的选择。
洛朗

23

如果您正在处理Firebase项目,则可以在Cloud Function中创建签名的URL,而无需包括其他库或下载凭据文件。您只需要启用IAM API并将角色添加到现有服务帐户即可(请参见下文)。

初始化管理库,并按照通常的方式获取文件引用:

import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'

admin.initializeApp(functions.config().firebase)

const myFile = admin.storage().bucket().file('path/to/my/file')

然后,您使用

myFile.getSignedUrl({action: 'read', expires: someDateObj}).then(urls => {
    const signedUrl = urls[0]
})

确保您的Firebase服务帐户具有足够的权限来运行此服务

  1. 转到Google API控制台并启用IAM API(https://console.developers.google.com/apis/api/iam.googleapis.com/overview
  2. 仍在API控制台中,转到主菜单“ IAM和管理员”->“ IAM”
  3. 单击“ App Engine默认服务帐户”角色的编辑
  4. 单击“添加其他角色”,然后添加一个名为“服务帐户令牌创建者”的角色
  5. 保存并等待一分钟,以使更改传播

使用原始Firebase配置时,首次运行上述代码时,您将得到一个错误,之前在项目XXXXXX中未使用过身份和访问管理(IAM)API,或者已将其禁用。。如果您遵循错误消息中的链接并启用IAM API,则会收到另一个错误:权限iam.serviceAccounts.signBlob需要在服务帐户my-service-account上执行此操作。添加令牌创建者角色可以解决第二个权限问题。


我将要用基本相同的细节留下答案,我终于想出了很难的方法-希望我早些时候通读了以下解决方案:/从18/12/12开始,这对我有用。感谢您的详细说明,对我们的初学者非常有帮助!
凯特

2
我的signedurl将在2周后过期,但是我使用的是admin.initializeApp(),没有密钥,这是问题吗?我已将App Engine应用程序默认服务帐户设置为“所有者”,并已将Cloud Functions Service Agent设置为Clouder Service Agent,现在我刚刚删除了“所有者”并添加了“服务帐户令牌创建者”
Amit Bravo

2
签名的URL将在7天后过期。您可以设置更短的到期日期,但不能更长。
Thomas David Kehoe

如果URL过期,如何刷新?
Manoj MM

如何刷新URL以将其设置为更长的时间?
赛法拉克19'Jul

17

成功使用的一种方法是firebaseStorageDownloadTokens,在文件上传完成后,将UUID v4值设置为文件元数据中命名的键,然后按照Firebase用来生成这些URL的结构自行组装下载URL,例如:

https://firebasestorage.googleapis.com/v0/b/[BUCKET_NAME]/o/[FILE_PATH]?alt=media&token=[THE_TOKEN_YOU_CREATED]

我不知道使用此方法有多少“安全”(鉴于Firebase将来可以更改其生成下载URL的方式),但是它易于实现。


1
您是否有设置uuid值的示例?
德鲁·博普雷

1
我和Drew有相同的问题,您在哪里设置元数据?我尝试在bucket.upload函数中进行设置,但无效。
Vysakh Sreenivasan

1
Vysakh,我已举了完整的答案(附示例)。希望对您有帮助。
德鲁·博普雷

您在哪里/如何创建令牌?
CodyBugstein

3
我不认为这种技术是“安全的”,因为下载URL的含义是不透明的,其组件不会被分解或组装。
道格·史蒂文森

16

对于那些想知道Firebase Admin SDK serviceAccountKey.json文件应该放在哪里的人。只需将其放置在functions文件夹中并照常部署即可。

仍然让我感到困惑的是,为什么我们不能像Javascript SDK那样从元数据中获取下载URL。生成最终将过期的URL并将其保存在数据库中是不可取的。


15

我建议在predefinedAcl: 'publicRead'通过Cloud Storage NodeJS 1.6.x或+ 上传文件时使用该选项:

const options = {
    destination: yourFileDestination,
    predefinedAcl: 'publicRead'
};

bucket.upload(attachment, options);

然后,获取公共URL很简单:

bucket.upload(attachment, options).then(result => {
    const file = result[0];
    return file.getMetadata();
}).then(results => {
    const metadata = results[0];
    console.log('metadata=', metadata.mediaLink);
}).catch(error => {
    console.error(error);
});

2
实际上,这确实可行。到目前为止,我唯一看到的缺点是,如果您在浏览器的URL栏中单击该图像,它将下载该图像,而不是内联查看。
Michael Giovanni Pumo

在文件引用上使用save()方法后,file.getMetadata()为我完成了窍门。在带有Firebase-admin SDK的NodeJS中使用它。
Pascal Lamers

没有工作,我得到匿名呼叫者没有storage.objects.get访问your_app / image.jpg
Manoj MM

9

抱歉,由于缺少声望,我无法在上面对您的问题发表评论,因此我将在此答案中提供它。

如上所述,通过生成一个已签名的Url进行操作,但我认为不必使用service-account.json,而必须使用可以在以下位置生成的serviceAccountKey.json(相应地替换YOURPROJECTID)

https://console.firebase.google.com/project/YOURPROJECTID/settings/serviceaccounts/adminsdk

例:

const gcs = require('@google-cloud/storage')({keyFilename: 'serviceAccountKey.json'});
// ...
const bucket = gcs.bucket(bucket);
// ...
return bucket.upload(tempLocalFile, {
        destination: filePath,
        metadata: {
          contentType: 'image/jpeg'
        }
      })
      .then((data) => {
        let file = data[0]
        file.getSignedUrl({
          action: 'read',
          expires: '03-17-2025'
        }, function(err, url) {
          if (err) {
            console.error(err);
            return;
          }

          // handle url 
        })

9

我无法评论James Daniels给出的答案,但是我认为这很重要。

像他一样给出一个签名的URL在许多情况下看起来都很糟糕,甚至有危险。根据Firebase的文档,签名的URL会在一段时间后过期,因此将其添加到您的数据库中将导致在特定时间段后出现一个空URL。

可能是误解了那里的文档,并且签名的url没有过期,因此会带来一些安全问题。每个上载文件的密钥似乎都相同。这意味着,一旦您获得一个文件的url,则只要知道它们的名称,某人就可以轻松访问他不应该访问的文件。

如果我误解了,那我会改正。其他人可能应该更新上述命名的解决方案。如果我在那里错了


7

这就是我目前使用的方法,它很简单并且可以完美地工作。

您无需对Google Cloud做任何事情。它可以与Firebase一起使用。

// Save the base64 to storage.
const file = admin.storage().bucket('url found on the storage part of firebase').file(`profile_photos/${uid}`);
await file.save(base64Image, {
    metadata: {
      contentType: 'image/jpeg',
    },
    predefinedAcl: 'publicRead'
});
const metaData = await file.getMetadata()
const url = metaData[0].mediaLink

编辑:相同的示例,但与上载:

await bucket.upload(fromFilePath, {destination: toFilePath});
file = bucket.file(toFilePath);
metaData = await file.getMetadata()
const trimUrl = metaData[0].mediaLink

更新:

无需在上载方法中进行两次不同的调用即可获取元数据:

let file = await bucket.upload(fromFilePath, {destination: toFilePath});
const trimUrl = file[0].metaData.mediaLink

1
您如何将其与未使用base64编码的文件一起使用?
Tibor Udvari

1
它不是mediaLinkenter,而是mediaLink
l2aelba,

1
我找不到mediaLink i.stack.imgur.com/B4Fw5.png
莎拉

@Sarah我用打字稿写的,不确定是否有模块替换。
奥利弗·迪克森

3

我遇到了同样的问题,但是,我正在查看firebase函数示例的代码,而不是README。而且对此线程的回答也没有帮助...

您可以通过执行以下操作避免传递配置文件:

转到项目的Cloud Console> IAM&admin> IAM,找到App Engine默认服务帐户,然后将Service Account Token Creator角色添加到该成员。这将使您的应用可以为图像创建签名的公共URL。

来源:自动生成缩略图功能自述文件

您在应用引擎中的角色应如下所示:

云端控制台


3

如果使用预定义的访问控制列表值“ publicRead”,则可以上传文件并使用非常简单的url结构进行访问:

// Upload to GCS
const opts: UploadOptions = {
  gzip: true,
  destination: dest, // 'someFolder/image.jpg'
  predefinedAcl: 'publicRead',
  public: true
};
return bucket.upload(imagePath, opts);

然后,您可以像这样构造网址:

const storageRoot = 'https://storage.googleapis.com/';
const bucketName = 'myapp.appspot.com/'; // CHANGE TO YOUR BUCKET NAME
const downloadUrl = storageRoot + bucketName + encodeURIComponent(dest);

2

如果您只需要带有简单URL的公共文件,则此方法有效。请注意,这可能会取代您的Firebase存储规则。

bucket.upload(file, function(err, file) {
    if (!err) {
      //Make the file public
      file.acl.add({
      entity: 'allUsers',
      role: gcs.acl.READER_ROLE
      }, function(err, aclObject) {
          if (!err) {
              var URL = "https://storage.googleapis.com/[your bucket name]/" + file.id;
              console.log(URL);
          } else {
              console.log("Failed to set permissions: " + err);
          }
      });  
    } else {
        console.log("Upload failed: " + err);
    }
});

1

对于使用Firebase SDK和的用户admin.initializeApp

1- 生成一个私钥并放置在/ functions文件夹中。

2-如下配置代码:

const serviceAccount = require('../../serviceAccountKey.json');
try { admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) })); } catch (e) {}

文献资料

尝试/捕获是因为我使用的index.js会导入其他文件,并为每个文件创建一个函数。如果您使用的是具有所有功能的单个index.js文件,则可以使用admin.initializeApp(Object.assign(functions.config().firebase, { credential: admin.credential.cert(serviceAccount) }));


对我来说,它是'../serviceaccountkey.json',但感谢您使用../
罗伯特·金

1

从firebase 6.0.0开始,我可以使用管理员直接访问存储,如下所示:

const bucket = admin.storage().bucket();

因此,我不需要添加服务帐户。然后按照上述参考设置UUID即可获取Firebase网址。


1

这是我最好的。这是多余的,但是对我有用的唯一合理的解决方案。

await bucket.upload(localFilePath, {destination: uploadPath, public: true});
const f = await bucket.file(uploadPath)
const meta = await f.getMetadata()
console.log(meta[0].mediaLink)

1

signedURL()使用makePublic()

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

admin.initializeApp()
var bucket = admin.storage().bucket();

// --- [Above] for admin related operations, [Below] for making a public url from a GCS uploaded object

const { Storage } = require('@google-cloud/storage');
const storage = new Storage();

exports.testDlUrl = functions.storage.object().onFinalize(async (objMetadata) => {
    console.log('bucket, file', objMetadata.bucket + ' ' + objMetadata.name.split('/').pop()); // assuming file is in folder
    return storage.bucket(objMetadata.bucket).file(objMetadata.name).makePublic().then(function (data) {
        return admin.firestore().collection('publicUrl').doc().set({ publicUrl: 'https://storage.googleapis.com/' + objMetadata.bucket + '/' + objMetadata.name }).then(writeResult => {
            return console.log('publicUrl', writeResult);
        });
    });
});


0

如果出现错误:

Google Cloud Functions:require(…)不是函数

试试这个:

const {Storage} = require('@google-cloud/storage');
const storage = new Storage({keyFilename: 'service-account-key.json'});
const bucket = storage.bucket(object.bucket);
const file = bucket.file(filePath);
.....

0

我已经在下面的URL中发布了我的回答...,您可以在其中获得完整的代码以及解决方案

如何使用Node.js将base64编码的图像(字符串)直接上传到Google Cloud Storage存储桶?

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();

    const os = require('os')
    const path = require('path')
    const cors = require('cors')({ origin: true })
    const Busboy = require('busboy')
    const fs = require('fs')
    var admin = require("firebase-admin");


    var serviceAccount = {
        "type": "service_account",
        "project_id": "xxxxxx",
        "private_key_id": "xxxxxx",
        "private_key": "-----BEGIN PRIVATE KEY-----\jr5x+4AvctKLonBafg\nElTg3Cj7pAEbUfIO9I44zZ8=\n-----END PRIVATE KEY-----\n",
        "client_email": "xxxx@xxxx.iam.gserviceaccount.com",
        "client_id": "xxxxxxxx",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-5rmdm%40xxxxx.iam.gserviceaccount.com"
      }

    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        storageBucket: "xxxxx-xxxx" // use your storage bucket name
    });


    const app = express();
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(bodyParser.json());
app.post('/uploadFile', (req, response) => {
    response.set('Access-Control-Allow-Origin', '*');
    const busboy = new Busboy({ headers: req.headers })
    let uploadData = null
    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
        const filepath = path.join(os.tmpdir(), filename)
        uploadData = { file: filepath, type: mimetype }
        console.log("-------------->>",filepath)
        file.pipe(fs.createWriteStream(filepath))
      })

      busboy.on('finish', () => {
        const bucket = admin.storage().bucket();
        bucket.upload(uploadData.file, {
            uploadType: 'media',
            metadata: {
              metadata: { firebaseStorageDownloadTokens: uuid,
                contentType: uploadData.type,
              },
            },
          })

          .catch(err => {
            res.status(500).json({
              error: err,
            })
          })
      })
      busboy.end(req.rawBody)
   });




exports.widgets = functions.https.onRequest(app);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.