从Java Servlet获取PDF后,Blob对象生成空PDF文件问题求助
问题:AEM Servlet返回PDF流,前端生成Blob后PDF为空
从AEM环境的Java Servlet获取到有效PDF文件,但前端用JavaScript创建Blob对象后,生成的PDF为空。接收的数据形态看似正常,但PDF无法正常显示。
Java端PDF流处理代码
private void streamPDF (final SlingHttpServletResponse response, final Resource pdfRes) throws IOException { String fileName = pdfRes.getPath().substring(pdfRes.getPath().lastIndexOf("/") + 1); response.setContentType("application/pdf"); response.setHeader("Content-disposition", "attachment; filename=" + fileName); Asset asset = pdfRes.adaptTo(Asset.class); final InputStream in = asset.getOriginal().getStream(); final OutputStream out = response.getOutputStream(); IOUtils.copy(in, out); out.close(); in.close(); }
JavaScript端请求及Blob创建代码
sendServletDownload: function (title, path) { let url = "myurl.pdf"; $.ajax({ url: url, type: 'GET', data: { path: path }, success: function (data) { var blob = new Blob([data], { type: 'application/pdf' }); // Create an URL object for the Blob var url = window.URL.createObjectURL(blob); // Configure the download link with the Blob's URL and the filename var downloadLink = document.getElementById('downloadLink'); downloadLink.href = url; downloadLink.download = title + '.pdf'; // Simulate a click in the link to iniciate the download downloadLink.click(); // Free the URL of the object when it's not necessary anymore window.URL.revokeObjectURL(url); }, error: function (XMLHttpRequest, textStatus, errorThrown) { console.log("Error: {}", errorThrown); }, xhrFields: { responseType: 'arraybuffer' // Stablish responseType to 'arraybuffer' } }); }
尝试过的base64解码代码
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; };
解决方案
1. 修正Java端流处理逻辑
- 确保输出流在复制完成后flush,避免缓冲区数据未写入响应:
IOUtils.copy(in, out); out.flush(); // 新增flush操作 out.close(); in.close(); - 添加
Content-Length响应头,让前端明确数据大小:long contentLength = asset.getOriginal().getSize(); response.setContentLengthLong(contentLength); - 改用try-with-resources自动管理流,避免手动关闭时的异常或遗漏:
private void streamPDF (final SlingHttpServletResponse response, final Resource pdfRes) throws IOException { String fileName = pdfRes.getPath().substring(pdfRes.getPath().lastIndexOf("/") + 1); response.setContentType("application/pdf"); response.setHeader("Content-disposition", "attachment; filename=" + fileName); Asset asset = pdfRes.adaptTo(Asset.class); try (InputStream in = asset.getOriginal().getStream(); OutputStream out = response.getOutputStream()) { response.setContentLengthLong(asset.getOriginal().getSize()); IOUtils.copy(in, out); out.flush(); } }
2. 前端AJAX处理优化
- 确认
responseType: 'arraybuffer'生效,可改用原生XMLHttpRequest测试,避免jQuery潜在的参数覆盖问题:sendServletDownload: function (title, path) { let url = "myurl.pdf?path=" + encodeURIComponent(path); let xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'arraybuffer'; xhr.onload = function() { if (xhr.status === 200) { var blob = new Blob([xhr.response], { type: 'application/pdf' }); var url = window.URL.createObjectURL(blob); var downloadLink = document.getElementById('downloadLink'); downloadLink.href = url; downloadLink.download = title + '.pdf'; downloadLink.click(); window.URL.revokeObjectURL(url); } }; xhr.send(); } - 无需将
arraybuffer类型数据转base64再解码,直接用原始响应数据创建Blob即可,转码会破坏二进制结构。
3. 排查响应头问题
- 检查Servlet返回的响应头是否存在
Transfer-Encoding: chunked,设置Content-Length后该头会被自动禁用,避免前端处理二进制数据异常。 - 确认没有其他AEM过滤器或组件向响应流中添加额外字符,这会导致PDF文件损坏。
内容的提问来源于stack exchange,提问作者Daniel Culebras
相关产品推荐
相关产品推荐

