繁体   English   中英

为什么 Node Pdfkit 偶尔会在我的代码中创建一个损坏的文件?

[英]Why Node Pdfkit creates occasionally a corrupted file in my code?

我有一个函数可以创建一个 pdf 文件并使用pdfkitnodemailer将它发送到电子邮件我nodemailer得到一个我无法打开的文件。 无法弄清楚为什么会发生这种情况以及为什么它在大多数情况下都有效? 我没有注意到失败时的任何特定情况,其中似乎没有任何公式(文本长度等)。 有人可以指出我的 pdf 创建代码中是否有一些明显的问题(比如 async/await)。

exports.sendTranscriptionToEmail = async (req, res) => {
  let finalText = [];
  let nickColorsArray = [];

  const doc = new PDFDocument();
  let filename = req.body.sessionName;
  let text = [];

  if (!filename || typeof filename != "string") {
    return res.status(400).send({ message: "Incorrect Information!" });
  }


// here I get the data from the database
  try {
    const rows = await knex("transcriptions").select("*").where({
      conversation_id: filename,
    });

    if (!rows) {
      return res.status(400).send({ message: "Transcription not found" });
    }



    // Stripping special characters
    filename = encodeURIComponent(filename) + ".pdf";

    res.setHeader(
      "Content-disposition",
      'attachment; filename="' + filename + '"'
    );
    res.setHeader("Content-type", "application/pdf");
    doc.pipe(fs.createWriteStream(filename));

    doc.fontSize(18).fillColor("black").text("Participants:", {
      width: 410,
      align: "center",
    });

    doc.moveDown();

    nickColorsArray.forEach((n) => {
      doc.fontSize(14).fillColor(n.color).text(n.nick, {
        width: 410,
        align: "center",
      });
    });

    doc.moveDown();
    doc.moveDown();

    doc.fontSize(18).fillColor("black").text("Transcription:", {
      width: 410,
      align: "center",
    });

    doc.moveDown();

    finalText.forEach((f) => {
      doc
        .fontSize(14)
        .fillColor(f.color)
        .text(f.word + " ", {
          width: 410,
          continued: true,
        });
    });

    doc.end();


   } catch (err) {
     console.log("Something went wrong: ", err.message);
   }

我遇到了同样的问题,经过调查,我在https://github.com/foliojs/pdfkit/issues/265找到了我的解决方案

PDFKit 实际上并不知道所有数据何时被刷新到您正在写入的任何流(文件、http 响应等)。 由于 PDFKit 无法访问它通过管道传输到的实际可写流(PDFKit 本身是一个可读流,并且您设置了可写部分),因此它只知道它何时完成向可能正在阅读的人输出块。 可写流实际将其内部缓冲区刷新到实际目的地可能需要一段时间。

我相信它不像在写流上监听“完成”事件那么简单,特别是在出现错误的情况下,所以我实现了以下返回 Promise 的函数。

function savePdfToFile(pdf : PDFKit.PDFDocument, fileName : string) : Promise<void> {
    return new Promise<void>((resolve, reject) => {

        // To determine when the PDF has finished being written successfully 
        // we need to confirm the following 2 conditions:
        //
        //   1. The write stream has been closed
        //   2. PDFDocument.end() was called syncronously without an error being thrown

        let pendingStepCount = 2;

        const stepFinished = () => {
            if (--pendingStepCount == 0) {
                resolve();
            }
        };

        const writeStream = fs.createWriteStream(fileName);
        writeStream.on('close', stepFinished);
        pdf.pipe(writeStream);

        pdf.end();

        stepFinished();
    }); 
}

您不是直接调用 .end() ,而是调用此函数并传递 pdf 文档和文件名。

这应该正确处理以下情况:

PDF 生成成功 在写入流关闭之前在 pdf.end() 中抛出错误 在写入流关闭后在 pdf.end() 中抛出错误

所以最后似乎有时服务器没有足够快地为您创建文件,在实施此解决方案后,我的响应时间确实增加了 1 秒,并摆脱了这种损坏行为

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM