【问题标题】:Node js, piping pdfkit to a memory streamNode js,将pdfkit管道传输到内存流
【发布时间】:2016-06-10 01:34:02
【问题描述】:

我在我的节点服务器上使用 pdfkit (https://github.com/devongovett/pdfkit),通常创建 pdf 文件,然后将它们上传到 s3。 问题是 pdfkit 示例将 pdf 文档通过管道传输到节点写入流中,该流将文件写入磁盘,我按照示例操作并正常工作,但是我现在的要求是将 pdf 文档传输到内存流而不是保存它在磁盘上(无论如何我正在上传到 s3)。 我已经遵循了一些节点内存流程序,但它们似乎都不适用于我的 pdf 管道,我可以将字符串写入内存流。 所以我的问题是:如何将 pdf 工具包输出通过管道传输到内存流(或类似的东西),然后将其作为对象读取以上传到 s3?

var fsStream = fs.createWriteStream(outputPath + fileName); 
doc.pipe(fsStream);

提前致谢。

【问题讨论】:

标签: node.js memorystream pdfkit


【解决方案1】:

2020 年的更新答案。无需引入新的内存流,因为“PDFDocument 实例是可读的节点流”。

您可以使用get-stream 包来轻松等待文档完成,然后再将结果返回给调用者。 https://www.npmjs.com/package/get-stream

const PDFDocument = require('pdfkit')
const getStream = require('get-stream')

const pdf = () => {
  const doc = new PDFDocument()
  doc.text('Hello, World!')
  doc.end()
  return await getStream.buffer(doc)
}


// Caller could do this:
const pdfBuffer = await pdf()
const pdfBase64string = pdfBuffer.toString('base64')

如果您的需求不同,您不必返回缓冲区。 get-stream 自述文件提供了其他示例。

【讨论】:

  • getStream.buffer 是我发现使它与 koa 一起工作的唯一方法。很好的帮助!
【解决方案2】:

无需使用中间内存流1 - 只需将 pdfkit 输出流直接通过管道传输到 HTTP 上传流。

根据我的经验,AWS SDK 在处理流时是垃圾,所以我通常使用request

var upload = request({
    method: 'PUT',
    url: 'https://bucket.s3.amazonaws.com/doc.pdf',
    aws: { bucket: 'bucket', key: ..., secret: ... }
});

doc.pipe(upload);

1 - 事实上,通常不希望使用内存流,因为这意味着在 RAM 中缓冲整个内容,而这正是流应该避免的!

【讨论】:

  • 我试过这个,但我似乎没有结束管道或结束request 使用的经验,所以我最终遇到了这个错误:[grunt-develop] > events.js:141 throw er; // Unhandled 'error' event ^ Error: read ECONNRESET at exports._errnoException (util.js:856:11) at TLSWrap.onread (net.js:544:26) >> application exited with code 1
  • 当一个可读流(这里是doc)结束时,它会自动告诉通过管道传送到的可写流(upload)它已经结束。如果您想知道可写(上传)何时完成,请收听finish event
  • 并且该堆栈跟踪表明您没有在正在断开连接的事物上侦听error 事件。添加error 侦听器,以便您可以准确确定断开连接的内容。如果是你的upload请求,那就太奇怪了。
  • 我添加了一个错误捕获器:upload.on('error', function (e) { console.log('error', e); });,它记录了error { [Error: read ECONNRESET] code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' }
【解决方案3】:

您可以尝试这样的事情,然后在 end 事件中将其上传到 S3。

var doc = new pdfkit();

var MemoryStream = require('memorystream');
var memStream = new MemoryStream(null, {
   readable : false
});

doc.pipe(memStream);

doc.on('end', function () {
   var buffer = Buffer.concat(memStream.queue);
   awsservice.putS3Object(buffer, fileName, fileType, folder).then(function () { }, reject);
})

【讨论】:

  • 您好 bolav,感谢您的建议,但我的问题是我不想在服务器上使用fs.createWriteStream
  • 是的。我以为你明白你能够替换我所做的,以证明我可以用上传到 S3 的内容将其写入文件。如何将文件上传到 S3?
  • awsservice.putS3Object(objectToUpload, fileName, fileType, folder).then(function () { }, reject);
  • 这里不能插入putS3Object的实现,因为cmets允许的字符太少了。
  • 嘿,谢谢!它对我有用。我需要将 PDF 设为临时文件,然后使用文件路径。
【解决方案4】:

我为 pdfkit 返回 base64 的代码:

import * as PDFDocument from 'pdfkit'
import getStream from 'get-stream'

const pdf = {
  createPdf: async (text: string) => {
    const doc = new PDFDocument()
    doc.fontSize(10).text(text, 50, 50)
    doc.end()

    const data = await getStream.buffer(doc)
    let b64 = Buffer.from(data).toString('base64')
    return b64
  }
}

export default pdf

【讨论】:

    【解决方案5】:

    @bolav 答案的调整对我尝试使用 pdfmake 而不是 pdfkit 有效。首先,您需要使用npmyarnmemorystream 添加到您的项目中。

    const MemoryStream = require('memorystream');
    const PdfPrinter = require('pdfmake');
    const pdfPrinter = new PdfPrinter();
    const docDef = {};
    const pdfDoc = pdfPrinter.createPdfKitDocument(docDef);
    const memStream = new MemoryStream(null, {readable: false});
    const pdfDocStream = pdfDoc.pipe(memStream);
    pdfDoc.end();
    pdfDocStream.on('finish', () => {
      console.log(Buffer.concat(memStream.queue);
    });
    

    【讨论】:

      猜你喜欢
      • 2014-07-11
      • 1970-01-01
      • 2022-10-13
      • 2016-09-17
      • 2014-07-09
      • 2019-10-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多