如何使用 pdfmake 生成 pdf 并将其存储在具有 firebase 云功能的 firebase 存储中

How to generate pdf with pdfmake and store it at firebase storage with firebase cloud functions

我正在用 firebase 开发一个应用程序。创建订单后,我想生成其发票。我已经实现了该功能,但是 URLs 有问题,因为创建了 pdf,但是正如您在图像中看到的那样,打开它的 URL 是错误的。

这是我在 Cloud Function 中的代码 index.js:

'use strict';

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const nodemailer = require('nodemailer');
//...

var PdfPrinter = require('pdfmake');
const fs = require('fs');

var fonts = {
  Courier: {
    normal: 'Courier',
    bold: 'Courier-Bold',
    italics: 'Courier-Oblique',
    bolditalics: 'Courier-BoldOblique'
  },
  Helvetica: {
    normal: 'Helvetica',
    bold: 'Helvetica-Bold',
    italics: 'Helvetica-Oblique',
    bolditalics: 'Helvetica-BoldOblique'
  },
  Times: {
    normal: 'Times-Roman',
    bold: 'Times-Bold',
    italics: 'Times-Italic',
    bolditalics: 'Times-BoldItalic'
  },
  Symbol: {
    normal: 'Symbol'
  },
  ZapfDingbats: {
    normal: 'ZapfDingbats'
  }
};

exports.generateInvoice = functions.database.ref('/pedidos/{documentId}').onCreate((snap, context) => {
  return (async () => {
    var docDefinition = {
      pageSize: 'A4',
      pageOrientation: 'portrait',
      content: [
        //Cabecera
        { image: 'img/logo.png', width: 90, alignment: 'left' },
        { text: `Pedido${snap.key}`, fontSize: 32, margin: [0, 8, 0, 0] }
      
        //Body
      ],
      defaultStyle: {
        font: 'Helvetica'
      }
    };
    console.log("Doc defined okey");

    const pdfName = snap.key + ".pdf";
    const fileName = "pedidos/" + pdfName;
    const myPDFfile = admin.storage().bucket().file(fileName);

    var printer = new PdfPrinter(fonts);
    var pdfDoc = printer.createPdfKitDocument(docDefinition);
    pdfDoc.pipe(myPDFfile.createWriteStream());
    pdfDoc.end();

  })().then(() => {

  }).catch (err => {
    console.log("An error has ocurred " + err);
  });
});

如您所见,pdf 已正确创建,但 URL 错误,我无法打开它。

如果有人帮助我,我将不胜感激。

这是通过 Admin SDK 将文件上传到 Cloud Storage 时的一个已知问题,请参阅 https://github.com/firebase/firebase-admin-node/issues/694

如您所见,主要有两种可能的方法:

  • 使用 getSignedUrl() 方法获得签名的 URL(允许有限时间访问文件)并将其保存在某处,例如在实时数据库或 Firestore 中。由于它的使用寿命有限,您可能需要根据您的功能要求定期更新它,例如通过预定的 Cloud Function。
  • 向文件元数据添加 firebaseStorageDownloadTokens 值。虽然它似乎有效(请参阅下面的代码),但似乎也不推荐,因为它不是官方 Google 云存储功能,请参阅 here

如果您想使用第二个选项(尽管它似乎不被推荐),以下方法可以解决问题:

const pdfDoc = printer.createPdfKitDocument(docDefinition);
pdfDoc.pipe(myPDFfile.createWriteStream());

pdfDoc.on('end', async function () {
   const uniqueId = admin.firestore().collection("_").doc().id;
   await myPDFfile.setMetadata({
        metadata: {
           firebaseStorageDownloadTokens: uniqueId,
        }
   });
});

pdfDoc.end();

不过,我会推荐第一种方法,即 getSignedUrl() 方法。