【问题标题】:Why Node Pdfkit creates occasionally a corrupted file in my code?为什么 Node Pdfkit 偶尔会在我的代码中创建损坏的文件?
【发布时间】:2020-08-27 09:28:35
【问题描述】:

我有一个函数可以创建一个 pdf 文件并使用 pdfkitnodemailer 将其发送到电子邮件中,有时我会收到一个无法打开的文件。无法弄清楚为什么会发生这种情况以及为什么它大部分时间都有效?当它失败时,我没有注意到任何特定情况,其中似乎没有任何公式(文本长度等)。有人可以指出我的 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);
   }

【问题讨论】:

  • 看不到你在任何地方返回你的流:)

标签: javascript node.js asynchronous async-await pdfkit


【解决方案1】:

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

PDFKit 实际上并不知道所有数据何时刷新到 您正在写入的任何流(文件、http 响应等)。自从 PDFKit 无法访问它正在通过管道传输的实际可写流 to (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 秒并摆脱了这种损坏行为

【讨论】:

    猜你喜欢
    • 2013-10-20
    • 1970-01-01
    • 2019-11-23
    • 1970-01-01
    • 1970-01-01
    • 2013-11-21
    • 2011-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多