使用 Firebase 函数获取上传到 Firebase 存储的 pdf 的签名下载 URL

Posted

技术标签:

【中文标题】使用 Firebase 函数获取上传到 Firebase 存储的 pdf 的签名下载 URL【英文标题】:Get Signed Download URL of pdf uploaded to Firebase Storage with Firebase Functions 【发布时间】:2018-10-09 21:00:24 【问题描述】:

在谷歌上花费了很多时间和无数小时的文档阅读之后,我来到这里提出这个问题,因为我没有取得任何进展。

我正在尝试使用 firebase 函数将文件上传到 Firebase 存储,然后在 firebase 函数完成时获取下载 url 以发回。

首先,我在index.js 的顶部添加了firebase-admin@google-cloud/storage。并初始化它们。

const storage = require('@google-cloud/storage');
const functions = require('firebase-functions');
const admin = require("firebase-admin");

admin.initializeApp(
   credential: admin.credential.cert( 
       // removed for security
       // This block was provided by Firebase Admin SDK 
       // under service accounts in settings of Firebase.
   ),
   databaseUrl: //removed for security,
   storageBucket: //removed for security
);

最后,我的函数创建了一个 firebase 数据库记录,生成一个 PDF 并将该文件存储在 firebase 存储中,然后应该返回一个有效的 url 来获取 pdf。

exports.createInvoice = functions.https.onRequest((req, res) => 
    cors(req, res, () => 
        if(req.method == 'POST') 
            generateInvoiceNumber().then((number) => 
                req.body.number = number.number;
                req.body.created = admin.database.ServerValue.TIMESTAMP;
                var total = 0;
                var items = req.body.items;
                for (var i = items.length - 1; i >= 0; i--) 
                    total = total + (items[i].cost * items[i].qty);
                
                req.body.total = total.toFixed(2);
                admin.database().ref('invoices').push(req.body).then(function(response)
                    var html = // removed for brevity;
                    var file = admin.storage().bucket().file('/tmp/invoice-'+number.number+'.pdf');
                    htmlPdf.create(html).toStream(function(err, stream)
                        stream.pipe(file.createWriteStream());
                        //stream.on('finish', function()
                            const config = 
                                action: 'read',
                                expires: '03-09-2491',
                                contentType: 'application/pdf'
                            ;
                            admin.storage().bucket().file('tmp/invoice-'+number.number+'.pdf').getSignedUrl(config).then(signedUrls => 
                                res.status(200).send(signedUrls);
                            )
                        //);
                    );
                );
            ).catch(error => 
                res.status(500).send(error);
            )
         else 
            res.status(405).send('Method Not Allowed');
        
    );
);

唯一不能正常工作的部分是在我的函数末尾附近返回的 URL。

admin.storage().bucket().file('tmp/invoice-'+number.number+'.pdf').getSignedUrl(config).then(signedUrls => 
  res.status(200).send(signedUrls);
);

当我尝试在浏览器中访问返回的 url 时,出现以下错误。

The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.

【问题讨论】:

我知道这个问题之前已经在 *** 上被问过,因为我已经在这个平台上尝试了很多答案。请不要标记为重复,因为它们不需要相同的答案,很明显,因为我以前尝试过它们。 您是否需要使用所有这些属性来初始化管理 SDK,或者您可以只采用 Cloud Functions 为您的项目提供的默认配置吗?除非您需要在项目之外进行访问,否则您可以不带参数进行初始化以获取所有默认值。 【参考方案1】:

嗯,我正在做的事情是因为我正在使用类似的东西,我发现您在元数据中寻找的关键是 mediaLink。这是我的代码示例。

                  admin.storage().bucket().file(`home/home-carousel/$filename`).save(file, (data) => 
                if(!data)
                  res(admin.storage().bucket().file(`home/home-carousel/$filename`).getMetadata().mediaLink)
                
               )

res() 是你想要的部分!

编辑:getMetadata 返回一个您必须解决才能获取元数据的承诺,如果您不这样做,您的 mediaLink 将是未定义的。而且,有几个从 promise 传回的参数,像数组一样访问它们,我提供了一个代码示例。

const saveLocation = storage.bucket('salesportal-8b7ef.appspot.com').file(`home/home-carousel/$webPFileName`)
                  saveLocation.save(data, (stuff) => 
                    if(!stuff)
                      saveLocation.makePublic().then( () => 
                        saveLocation.getMetadata()
                        .then( (meta) => 
                          metadata = meta[0]
                            admin.firestore().collection("Pages").doc("home-carousel").set( homeCarousel : [`$filename`] :  webPUrl : `$metadata.mediaLink` , merge: true).then( 
                              () => 
                                resolve()
                              )
                        )

                      )
                    

【讨论】:

以上是关于使用 Firebase 函数获取上传到 Firebase 存储的 pdf 的签名下载 URL的主要内容,如果未能解决你的问题,请参考以下文章

Firebase Phone Auth 在发布版本中不起作用

Firebase 云函数中的 Object.values()

Firebase 存储图像无法正确上传

如何在 Firebase/Auth 上避免 UIWebView

如何以BLOB格式将图像上传到Firebase存储?

从 ArrayList 中的 Firebase 检索数据以获取图形