Node.js Nodemailer 附件的内存中的 Fetch() PDF 文件缓冲区
Node.js Fetch() PDF File Buffer In Memory for Nodemailer Attachment
我有一个夜间进程,它通过调用我创建的端点发送预定报告,该端点 returns PDF 格式的实时报告。
我 运行 遇到的问题是将从端点返回的二进制文件放入缓冲区,Nodemailer 可以使用该缓冲区附加 PDF 报告。
我只是在使用从 fetch() 和 arrayBuffer() 返回的 Promise。
我没有使用异步等待。
下面使用 arrayBuffer() 和 Buffer.from() 的代码片段有效,但我想知道是否有更有效的方法来处理这个问题,尤其是在处理大型 PDF 文件时。
我更喜欢在内存中工作而不是写入磁盘。我在 Express 中分配了大量内存,但还没有发现任何内存问题。
const sendPDFReport = (reportScheduleId, cb) => {
let scheduleObj;
//*** Get Report Schedule Data from MongoDB and Assign to scheduleObj
let emailAddresses = [];
//*** Push Recipient Emails into Email Array
//*** Do Work Like Build Fetch URL and Connection Properties Object ie.,
let fetchBody={};
//*** Build JSON object of POST Params and assign to fetchBody
let fetchURL = process.env.APPSERVER_URL+some_report_path;
let config = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(fetchBody),
responseType: 'blob'
};
let transporter = nodemailer.createTransport({
host: 'mail.whatever.com',
service: "Outlook365",
secure: true,
port: 465,
auth: {
user: process.env.NO_REPLY,
pass: process.env.NO_REPLY_PW
},
tls: {
ciphers: 'SSLv3',
rejectUnauthorized: false
}
});
fetch(fetchURL, config)
.then(response => {
if (response.ok) {
//*** PDF Binary Response Buffering for Nodemailer
response.arrayBuffer()
.then(resBufferAr => {
const pdfBuffer = Buffer.from(resBufferAr);
// **** Build Email mailOptions for Nodemailer Transporter Object ***
let mailOptions = {
from: process.env.NO_REPLY,
to: emailAddresses.join([separator = ',']),
subject: 'Scheduled Report: ' + scheduleObj.reportType + ' ' + scheduleObj.selectedReport,
html: '<h4> See Attached Report </h4>';
//*** Nodemailer Attachment Section
attachments: [{
filename: scheduleObj.reportType + '_' + scheduleObj.selectedReport + '_' + now + '.pdf',
content: pdfBuffer,
encoding: 'base64',
contentType: 'application/pdf'
}]
};
transporter.sendMail(mailOptions, function (err) {
if (err) {
console.log('Transporter Error: ' + err);
return cb(err);
}
return cb(null);
}
})
.catch((err) => {
console.log('Problem Processing Alert Notification: ' + err);
return cb(err);
})
return cb(null);
}
任何意见或建议都将是很好的。
是的,有一个更有效的方法:Streams
简而言之,流是 Node 中的内置数据结构,它允许您对传入数据块进行操作,而不是在处理之前等待整个数据加载到内存中。
node-fetch
支持 streams as response payloads and nodemailer
supports streams as attachments,因此您可以有效地将获取响应的主体通过管道传输到 nodemailer。从理论上讲,您的机器实际上从来没有在任何时候将整个 PDF 存储在内存中,而是只有 PDF 的一部分,当它们进入时,它只会从一侧网络传递到另一侧网络(尽管有一些原因这有时站不住脚)。
我还没有完全测试过这个,但这至少应该接近于涉及 node-fetch
和 nodemailer
之间的流的工作解决方案:
if (response.ok) {
let readableStream = response.body;
let mailOptions = {
from: process.env.NO_REPLY,
to: emailAddresses.join(','),
subject: 'Scheduled Report: ' + scheduleObj.reportType + ' ' + scheduleObj.selectedReport,
html: '<h4> See Attached Report </h4>',
attachments: [{
filename: scheduleObj.reportType + '_' + scheduleObj.selectedReport + '_' + now + '.pdf',
content: readableStream,
encoding: 'base64',
contentType: 'application/pdf'
}]
};
// ...the rest of your code
更新: 虽然我没有使用 node-fetch
,但我确实测试了内存使用情况,从磁盘读取一个 3MB 的文件并通过 nodemailer
。将整个文件读入内存并将其传递给 nodemailer
后,驻留集大小 (rss) 约为 48MB,外部 C++ 堆约为 11MB。当给 nodemailer
文件的读取流时,rss 约为 37MB,外部堆约为 4MB。所以它肯定更有效率。
我有一个夜间进程,它通过调用我创建的端点发送预定报告,该端点 returns PDF 格式的实时报告。
我 运行 遇到的问题是将从端点返回的二进制文件放入缓冲区,Nodemailer 可以使用该缓冲区附加 PDF 报告。
我只是在使用从 fetch() 和 arrayBuffer() 返回的 Promise。 我没有使用异步等待。
下面使用 arrayBuffer() 和 Buffer.from() 的代码片段有效,但我想知道是否有更有效的方法来处理这个问题,尤其是在处理大型 PDF 文件时。
我更喜欢在内存中工作而不是写入磁盘。我在 Express 中分配了大量内存,但还没有发现任何内存问题。
const sendPDFReport = (reportScheduleId, cb) => {
let scheduleObj;
//*** Get Report Schedule Data from MongoDB and Assign to scheduleObj
let emailAddresses = [];
//*** Push Recipient Emails into Email Array
//*** Do Work Like Build Fetch URL and Connection Properties Object ie.,
let fetchBody={};
//*** Build JSON object of POST Params and assign to fetchBody
let fetchURL = process.env.APPSERVER_URL+some_report_path;
let config = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(fetchBody),
responseType: 'blob'
};
let transporter = nodemailer.createTransport({
host: 'mail.whatever.com',
service: "Outlook365",
secure: true,
port: 465,
auth: {
user: process.env.NO_REPLY,
pass: process.env.NO_REPLY_PW
},
tls: {
ciphers: 'SSLv3',
rejectUnauthorized: false
}
});
fetch(fetchURL, config)
.then(response => {
if (response.ok) {
//*** PDF Binary Response Buffering for Nodemailer
response.arrayBuffer()
.then(resBufferAr => {
const pdfBuffer = Buffer.from(resBufferAr);
// **** Build Email mailOptions for Nodemailer Transporter Object ***
let mailOptions = {
from: process.env.NO_REPLY,
to: emailAddresses.join([separator = ',']),
subject: 'Scheduled Report: ' + scheduleObj.reportType + ' ' + scheduleObj.selectedReport,
html: '<h4> See Attached Report </h4>';
//*** Nodemailer Attachment Section
attachments: [{
filename: scheduleObj.reportType + '_' + scheduleObj.selectedReport + '_' + now + '.pdf',
content: pdfBuffer,
encoding: 'base64',
contentType: 'application/pdf'
}]
};
transporter.sendMail(mailOptions, function (err) {
if (err) {
console.log('Transporter Error: ' + err);
return cb(err);
}
return cb(null);
}
})
.catch((err) => {
console.log('Problem Processing Alert Notification: ' + err);
return cb(err);
})
return cb(null);
}
任何意见或建议都将是很好的。
是的,有一个更有效的方法:Streams
简而言之,流是 Node 中的内置数据结构,它允许您对传入数据块进行操作,而不是在处理之前等待整个数据加载到内存中。
node-fetch
支持 streams as response payloads and nodemailer
supports streams as attachments,因此您可以有效地将获取响应的主体通过管道传输到 nodemailer。从理论上讲,您的机器实际上从来没有在任何时候将整个 PDF 存储在内存中,而是只有 PDF 的一部分,当它们进入时,它只会从一侧网络传递到另一侧网络(尽管有一些原因这有时站不住脚)。
我还没有完全测试过这个,但这至少应该接近于涉及 node-fetch
和 nodemailer
之间的流的工作解决方案:
if (response.ok) {
let readableStream = response.body;
let mailOptions = {
from: process.env.NO_REPLY,
to: emailAddresses.join(','),
subject: 'Scheduled Report: ' + scheduleObj.reportType + ' ' + scheduleObj.selectedReport,
html: '<h4> See Attached Report </h4>',
attachments: [{
filename: scheduleObj.reportType + '_' + scheduleObj.selectedReport + '_' + now + '.pdf',
content: readableStream,
encoding: 'base64',
contentType: 'application/pdf'
}]
};
// ...the rest of your code
更新: 虽然我没有使用 node-fetch
,但我确实测试了内存使用情况,从磁盘读取一个 3MB 的文件并通过 nodemailer
。将整个文件读入内存并将其传递给 nodemailer
后,驻留集大小 (rss) 约为 48MB,外部 C++ 堆约为 11MB。当给 nodemailer
文件的读取流时,rss 约为 37MB,外部堆约为 4MB。所以它肯定更有效率。