将PDF管道传递给Express Response会得到空白的PDF

时间:2018-11-07 21:27:47

标签: javascript express pdf character-encoding pdfkit

我正在尝试使用Lambda函数创建PDF,但是使用PDF Kit中的.pipe()函数时遇到了麻烦。打开下载的PDF时,它为空白。通过将PDF转换为base64字符串并打开它,我获得了成功,但是当PDF大小和请求数增加时,这将不可行。

我的理想方法是使用.pipe(),正如我在多本指南中所见。这是下面的代码,返回空白的PDF。我尝试在客户端上同时使用responseType: 'blob'responseType: arraybuffer。两者都打开空白文件。

let pdf = new PDFDocument();
pdf.text("hello world", 50, 50);

res.setHeader("Content-Type", "application/pdf");
res.setHeader(
  "Content-Disposition",
  `attachment; filename=test.pdf`
);
res.status(200);

pdf.pipe(res);
pdf.end();

这种方法有效,下载的PDF包含“ hello world”文本,但是由于性能/内存问题,这不是可行的方法。

let chunks = [];    
let pdf = new PDFDocument();

pdf.text("hello world", 50, 50);

pdf.on("data", data => {
  chunks.push(data);
});

pdf.on("end", () => {
  res.setHeader("Content-Type", "application/pdf");
  res.setHeader(
    "Content-Disposition",
    `attachment; filename=test.pdf`
  );
  res.status(200);
  const result = Buffer.concat(chunks);
  res.send(
    "data:application/pdf;base64," + result.toString("base64")
  ); 
});

pdf.end();

我检查了两个PDF文件的内容(通过上述两种方法),发现两者之间的实际内容有所不同。在Chrome中记录的原始响应中也观察到了这一点。我不会粘贴整个文件内容(除非有人认为这是必要的),但这是文件的不同之处:

空白PDF

stream
x�e�;
�0�=Ż���g� )-���*����7na'�c��pFǦ<yԛ�_[�d1�>�zӰ1�C�����ͻ��a��} .��d�J,pt�U���*
endstream

工作PDF

stream
xœeŒ;
€0û=Å»€šÍg£ )-ì„íÄ*ÎÂû7na'ÃcŠÇpFǦ<yÔ›â_[ô‹Œd1„>ŒzÓ°1ØC³Œ’¤Í»œØa––±«d³J,pt§Ué ÝÎ*
endstream

我对编码了解不多,所以不确定这是否有用还是只是乱码,但这确实表明两个文件之间的编码有所不同,也许我在Express中没有正确设置一些内容。

1 个答案:

答案 0 :(得分:0)

最后使用一种解决方法,将流转换为base64,然后在客户端中对其进行解码。

表达功能:

const { Base64Encode } = require("base64-stream");

let pdf = new PDFDocument();

pdf.text("hello world", 50, 50);
res.setHeader("Content-Type", "application/pdf");
res.setHeader(
  "Content-Disposition",
  `attachment; filename=test.pdf`
);

res.status(200);
pdf.pipe(new Base64Encode()).pipe(res);
pdf.end();

客户代码:

function base64ToArrayBuffer(data) {
  var binaryString = window.atob(data);
  var binaryLen = binaryString.length;
  var bytes = new Uint8Array(binaryLen);
  for (var i = 0; i < binaryLen; i++) {
    var ascii = binaryString.charCodeAt(i);
    bytes[i] = ascii;
  }
  return bytes;
}

// In my response handler:
const arraybuffer = base64ToArrayBuffer(response);
const blob = new Blob([arraybuffer], { type: "application/pdf" });
saveAs(blob, "test.pdf");