已下载的PDF虽然包含一些数据,但看起来是空的

时间:2018-08-23 08:34:35

标签: javascript jquery post itext blob

我正在尝试使用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();

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

当我测试生成PDF的Java服务器端模块时,一切正常,它通过InputStream发送ServletOutputStream。因此,我认为问题出在客户端的某个地方,也许是MIMEBLOBencoding或类似的东西。

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

2 个答案:

答案 0 :(得分: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();

客户端

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();

参考主题:

答案 1 :(得分:0)

谢谢。确实有效。

顺便说一句,这是我如何使用spring控制器和ajax以及jasper生成的pdf来实现

控制器:

public ResponseEntity<?> printPreview(@ModelAttribute("claim") Claim claim)
{
    try
    {
        //Code to get the byte[] from jasper report.
        ReportSource source = new ReportSource(claim);
        byte[] report = reportingService.exportToByteArrayOutputStream(source);

        //Conversion of bytes to Base64
        byte[] encodedBytes = java.util.Base64.getEncoder().encode(report);

        //Setting Headers
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/pdf"));
        headers.setContentDispositionFormData("pdfFileName.pdf", "pdfFileName.pdf");
        headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
        headers.setContentLength(encodedBytes.length);

        return new ResponseEntity<>(encodedBytes, headers, HttpStatus.OK);
    }
    catch (Exception e)
    {
        LOG.error("Error on generating report", e);
        return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
 }

ajax:

    $.ajax({
       type: "POST",
       url: "",
       data: form.serialize(), //Data from my form
       success: function(response)
       {
                let binaryString = window.atob(response);
                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 = URL.createObjectURL(blob);
                window.open(link, '_blank');
       },
       error: function()
       {

       }
     });

这将在新窗口中加载pdf。

参考:Return generated pdf using spring MVC