下载的PDF看起来是空的,尽管它包含一些数据

Mik*_* B. 2 javascript jquery post blob itext

我正在尝试使用JavaScript实现PDF文件下载功能.
作为对POST请求的响应,我得到一个PDF文件,在Chrome DevTools控制台中看起来像(oResult数据容器,片段):

"%PDF-1.4↵% ↵40obj↵<>stream↵x

现在我正在尝试初始化下载过程:

let blob = new Blob([oResult], {type: "application/pdf"});

let link = document.createElement('a');

link.href = window.URL.createObjectURL(blob);
link.download = "tstPDF";

link.click();
Run Code Online (Sandbox Code Playgroud)

结果,点击一个按钮我得到tstPDF.pdf,它包含正确的页数,但PDF本身是空的,没有显示内容,尽管它是6 KB.

当我测试生成PDF的Java服务器端模块时,一切正常,它InputStream通过发送ServletOutputStream.因此,我认为这个问题是地方上的客户端,或许有东西MIME,BLOB,encoding,或类似的.

您知道为什么生成的PDF不显示任何数据吗?

Mik*_* B. 5

我解决了这个问题.问题在于数据从服务器传递到客户端的方式.确保服务器以Base64编码方式发送数据至关重要,否则客户端无法将PDF字符串反序列化为二进制格式.下面,您可以找到完整的解决方案.

服务器端:

OutputStream pdfStream = PDFGenerator.pdfGenerate(data);

String pdfFileName = "test_pdf";

// represent PDF as byteArray for further serialization
byte[] byteArray = ((java.io.ByteArrayOutputStream) pdfStream).toByteArray();

// serialize PDF to Base64
byte[] encodedBytes = java.util.Base64.getEncoder().encode(byteArray);

response.reset();
response.addHeader("Pragma", "public");
response.addHeader("Cache-Control", "max-age=0");
response.setHeader("Content-disposition", "attachment;filename=" + pdfFileName);
response.setContentType("application/pdf");

// avoid "byte shaving" by specifying precise length of transferred data
response.setContentLength(encodedBytes.length);

// send to output stream
ServletOutputStream servletOutputStream = response.getOutputStream();

servletOutputStream.write(encodedBytes);
servletOutputStream.flush();
servletOutputStream.close();
Run Code Online (Sandbox Code Playgroud)

客户端:

let binaryString = window.atob(data);

let binaryLen = binaryString.length;

let bytes = new Uint8Array(binaryLen);

for (let i = 0; i < binaryLen; i++) {
    let ascii = binaryString.charCodeAt(i);
    bytes[i] = ascii;
}

let blob = new Blob([bytes], {type: "application/pdf"});

let link = document.createElement('a');

link.href = window.URL.createObjectURL(blob);
link.download = pdfFileName;

link.click();
Run Code Online (Sandbox Code Playgroud)

参考主题:

  • 虽然它有效,但当 pdf 文件变得很大时我不会使用它。这在服务器上都是有问题的,其中 toByteArray 在内存中制作数据副本,然后编码制作另一个副本,大约大 1.4 倍。在客户端也很糟糕:你有一次数据,然后是binaryString,然后是字节,然后是blob。也许您需要这个:/sf/answers/1169827781/ (3认同)
  • 很好的答案!如果我看到遇到同样问题的人提出的问题,这将有助于进一步参考。 (2认同)