使用firebase-admin上传文件后获取公共URL

13

我使用firebase-admin和firebase-functions在Firebase Storage中上传文件。

我在Storage中有这些规则:

service firebase.storage {
  match /b/{bucket}/o {
    match /images {
      allow read;
      allow write: if false;
    }
  }
}

我想用这段代码获取一个公共URL:

const config = functions.config().firebase;
const firebase = admin.initializeApp(config);
const bucketRef = firebase.storage();

server.post('/upload', async (req, res) => {

  // UPLOAD FILE

  await stream.on('finish', async () => {
        const fileUrl = bucketRef
          .child(`images/${fileName}`)
          .getDownloadUrl()
          .getResult();
        return res.status(200).send(fileUrl);
      });
});

但是我遇到了这个错误.child不是一个函数。如何使用firebase-admin获取文件的公共URL?

3个回答

13

使用云存储文档的示例应用程序代码中,您应该能够实现以下代码,在上传成功后获取公共下载URL:

// Create a new blob in the bucket and upload the file data.
const blob = bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream();

blobStream.on('finish', () => {
    // The public URL can be used to directly access the file via HTTP.
    const publicUrl = format(`https://storage.googleapis.com/${bucket.name}/${blob.name}`);
    res.status(200).send(publicUrl);
});

或者,如果您需要一个公开可访问的下载URL,请参见此答案,该答案建议使用Cloud Storage NPM模块中的getSignedUrl(),因为Admin SDK不支持直接这样做:

You'll need to generate a signed URL using getSignedURL via the @google-cloud/storage NPM module.

Example:

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

1
是的,@Grimthorr,但匿名用户无法访问该文件。 - SaroVin
1
啊,抱歉,你是想获取公共访问的下载URL吗?请看这个答案 - 使用Firebase云函数上传文件后获取下载链接 - 看起来仅凭Admin SDK是不可能实现的。 - Grimthorr
是的,我知道这种方法,但我不喜欢这个解决方案,因为URL太长了。不管怎样,这似乎是唯一的办法。 - SaroVin
1
不幸的是,由于管理 SDK 的限制,我认为这是唯一的路线。我猜你可以通过谷歌的 URL 缩短 API传递 URL,但这又增加了一个步骤。我已经根据其他答案中的细节更新了我的答案。 - Grimthorr
1
Admin SDK在底层使用@google-cloud/storage。由admin.storage().bucket()返回的bucket对象来自该包。因此,您无需重新初始化GCS包。只要您已经使用服务帐号初始化了Admin SDK,就应该能够在从API获取的文件引用上调用getSignedUrl() - Hiranya Jayathilaka

5

对我有效的方法是编写像这样的URL:

https://storage.googleapis.com/<bucketName>/<pathToFile>

示例:https://storage.googleapis.com/mybucket.appspot.com/public/myFile.png

我是如何找到它的?

我进入了GCP控制台,选择存储。找到已上传的文件。点击“复制URL”。

您可能需要先将文件设置为公开。我是这样做的:

const bucket = seFirebaseService.admin().storage().bucket()
await bucket.file(`public/myFile.png`).makePublic()

这是正确的方法,它允许您使用 AJAX 请求访问文件,例如 JSON 数据。 - holmberd
这对我也起作用了,而且比被接受的解决方案简单得多。在将makePublic()应用于文件之后,从publicUrl()返回的URL可以公开和匿名地访问。 - Gorgant

3
我已经折腾了几天,意识到:
A)正确的存储桶访问权限至关重要:
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read;
      allow write: if request.auth != null;
    }
  }
}

B)功能性的公共URL就在元数据中(已测试并有效)。请注意访问权限。
  const pdfDoc = printer.createPdfKitDocument(docDefinition);
  const pdfFile = admin
      .storage()
      .bucket()
      .file(newId + '.pdf');

    pdfDoc.pipe(
      pdfFile.createWriteStream({
        contentType: 'application/pdf',
        public: true,
      })
    );
    pdfDoc.end();

    console.log('Get public URL');
    const publicUrl = pdfFile.metadata.mediaLink;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接