Luk*_*ker 6 node.js firebase google-cloud-functions
我正在开发Firebase函数,当向实时数据库中添加新订单时会触发该函数。它要做的第一件事是创建pdf并将其通过管道传输到Google云存储桶。
在存储区流的.on(“ finish”)事件上,下一个函数启动,该函数应通过电子邮件将管道的pdf发送给客户。
一切似乎都正常,至少有一点。
首先,我遇到了一个问题,即所附的pdf始终为空。(不仅是空白。我还用记事本++打开了它,实际上它全是空的)。当我检查bucketFileStream.on(“ finished”)函数内的doc和bucketFileSream变量的长度均为0时。直接在doc.end之后检查doc var的长度为612。
然后,我更改了流程,即在sendOrderEmail函数中,我还从存储桶中新创建的File中打开了一个新的Read Stream。
现在,我至少在附件中得到了一些PDF内容,但是没有获得全部内容。
当我检查上传到存储桶的PDF时,看起来应该是这样。
我在Google上搜索了很多,找到了一些也针对该主题的答案,但是正如对这些问题的评论所看到的那样,它们并没有完全帮助。
我还与nodemailer文档一起检查了如何正确传递附件并按文档所述实施了附件。但是没有成功。
我认为邮件是在读取流完成之前发送的。
这是我使用的软件包版本:
谁能告诉我我做错了什么,或提供一个使用此案例的使用当前软件包版本的有效示例?
这是令我疯狂的代码...
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const nodemailer = require("nodemailer");
const pdfkit = require("pdfkit");
const storage = require("@google-cloud/storage")({projectId: `${PROJECT_ID}`})
const mailTransport = nodemailer.createTransport({
host: "smtp.office365.com",
port: 587,
secureConnection: false,
auth: {
user: "userName",
pass: "userPassword"
},
tls: {
ciphers: "SSLv3",
}
});
exports.added = function(event) {
const order = event.data.val();
const userId = event.params.userId;
// Load User Data by userId
return admin
.database()
.ref("/users/" +userId)
.once("value")
.then(function (snapshot) {
return generateOrderPDF(snapshot.val(), userId);
});
};
function generateOrderPDF(user, userId) {
const doc = new pdfkit();
const bucket = storage.bucket(functions.config().bucket);
const filename = `/${userId}/test-` + Date.now() + ".pdf";
const file = bucket.file(filename);
const bucketFileStream = file.createWriteStream();
// Pipe its output to the bucket
doc.pipe(bucketFileStream);
// Do creation Stuff....
doc.end();
bucketFileStream.on("finish", function () {
return sendOrderEmail(user, filename);
});
bucketFileStream.on("error", function(err) {
console.error(err);
});
}
function sendOrderEmail(user, filename) {
const email = user.email;
const firstname = user.firstName;
const mailOptions = {
from: "test@test.test",
to: email,
subject: "Order"
};
const bucket = storage.bucket(functions.config().bucket);
const file = bucket.file(filename);
mailOptions.html = mailTemplate;
mailOptions.attachments = [{
filename: "test.pdf",
content: file.createReadStream()
}];
return mailTransport.sendMail(mailOptions).then(() => {
console.log("New order email sent to:", email);
}).catch(error => {
console.error(error);
});
}
Run Code Online (Sandbox Code Playgroud)
The problem in my appraoch was inside the pdfkit library and not inside nodemailer or firebase. The lines below seem to trigger the end event. So the pdf got sent after these lines. After out commenting them everything worked as it should. It was not that finish was never reached like Hari mentioned.
/* doc.lineCap("underline")
.moveTo(72, 321)
.lineTo(570, 321)
.stroke();*/
Run Code Online (Sandbox Code Playgroud)
After finishing the MVP I will take a root cause analysis and post the final answer as comment below this answer.
This is a working sample of Source-Code for this UseCase. It also ensures, that the firebase function won't finish before all work is done. That is handled by wrapping the event driven doc.on() function into a promise, that is resolved when doc.on("end") is called.
/* doc.lineCap("underline")
.moveTo(72, 321)
.lineTo(570, 321)
.stroke();*/
Run Code Online (Sandbox Code Playgroud)
小智 5
代码中的主要问题是stream.on('finish')永远不会完成。我也遇到了同样的问题。
不是流式传输,而是将 pdf 转换为缓冲区并作为附件发送。
以下对我来说效果很好,
const doc = new pdfkit()
const filename = '/${userId}/test-' + Date.now() + ".pdf"
const file = bucket.file(filename);
const bucketFileStream = file.createWriteStream();
doc.pipe(bucketFileStream);
doc.end();
var buffers = []
doc.on('data', buffers.push.bind(buffers));
doc.on('end',function(){
let pdfData = Buffer.concat(buffers);
'<<nodemailer stuffs goes here>
'attach the doc as content
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4590 次 |
| 最近记录: |