如何使用JavaScript从Web服务返回的二进制string构buildPDF文件
我正尝试从二进制stream中构build一个PDF文件,作为ajax请求的响应接收。
通过XmlHttpRequest我收到以下数据:
%PDF-1.4.... ..... ....hole data representing the file .... %% EOF
我到目前为止所尝试的是通过数据embedded我的数据:uri。
现在,这没什么不妥。 它工作正常。 不幸的是,它不能在IE9和FF中工作。
可能的原因可能是FF和IE9在使用data-uri时存在问题。
现在,我正在寻找适用于所有浏览器的解决scheme。
这是我的代码:
// responseText encoding pdfText=$.base64.decode($.trim(pdfText)); // Now pdfText contains %PDF-1.4 ...... data...... %%EOF var winlogicalname = "detailPDF"; var winparams = 'dependent=yes,locationbar=no,scrollbars=yes,menubar=yes,'+ 'resizable,screenX=50,screenY=50,width=850,height=1050'; var htmlText = '<embed width=100% height=100%' + ' type="application/pdf"' + ' src="data:application/pdf,' + escape(pdfText) + '"></embed>'; // Open PDF in new browser window var detailWindow = window.open ("", winlogicalname, winparams); detailWindow.document.write (htmlText); detailWindow.document.close ();
正如我所说的….它适用于Opera和Chrome(Safari未经testing)。 使用IE或FF会popup一个空白的新窗口。
是否有任何解决scheme,如build立在文件系统的PDF文件,以让用户下载?
至less在IE,FF,Opera,Chrome和Safari中,我需要一个适用于所有浏览器的解决scheme。
我没有权限编辑Web服务实现。 所以它必须是客户端的一个解决scheme。
有任何想法吗???
是否有任何解决scheme,如build立在文件系统的PDF文件,以让用户下载?
尝试将XMLHttpRequest
responseType
设置为blob
,将window.open
a
元素的download
属性replace为允许将XMLHttpRequest
的响应下载为.pdf
文件
var request = new XMLHttpRequest(); request.open("GET", "/path/to/pdf", true); request.responseType = "blob"; request.onload = function (e) { if (this.status === 200) { // `blob` response console.log(this.response); // create `objectURL` of `this.response` : `.pdf` as `Blob` var file = window.URL.createObjectURL(this.response); var a = document.createElement("a"); a.href = file; a.download = this.response.name || "detailPDF"; document.body.appendChild(a); a.click(); // remove `a` following `Save As` dialog, // `window` regains `focus` window.onfocus = function () { document.body.removeChild(a) } }; }; request.send();
我意识到这是一个相当古老的问题,但这是我今天提出的解决scheme:
doSomethingToRequestData().then(function(downloadedFile) { // create a download anchor tag var downloadLink = document.createElement('a'); downloadLink.target = '_blank'; downloadLink.download = 'name_to_give_saved_file.pdf'; // convert downloaded data to a Blob var blob = new Blob([downloadedFile.data], { type: 'application/pdf' }); // create an object URL from the Blob var URL = window.URL || window.webkitURL; var downloadUrl = URL.createObjectURL(blob); // set object URL as the anchor's href downloadLink.href = downloadUrl; // append the anchor to document body document.body.append(downloadLink); // fire a click event on the anchor downloadLink.click(); // cleanup: remove element and revoke object URL document.body.removeChild(downloadLink); URL.revokeObjectURL(downloadUrl); }
我改变了这个:
var htmlText = '<embed width=100% height=100%' + ' type="application/pdf"' + ' src="data:application/pdf,' + escape(pdfText) + '"></embed>';
至
var htmlText = '<embed width=100% height=100%' + ' type="application/pdf"' + ' src="data:application/pdf;base64,' + escape(pdfText) + '"></embed>';
它为我工作。
我在PHP中工作,并使用函数来解码从服务器发回的二进制数据。 我提取信息input到一个简单的file.php,并通过我的服务器查看文件,所有浏览器显示PDF文件。
<?php $data = 'dfjhdfjhdfjhdfjhjhdfjhdfjhdfjhdfdfjhdf==blah...blah...blah..' $data = base64_decode($data); header("Content-type: application/pdf"); header("Content-Length:" . strlen($data )); header("Content-Disposition: inline; filename=label.pdf"); print $data; exit(1); ?>
最近我看到了另外一个关于这个主题的问题( 使用dataurl将PDF转换为iframe,只能在chrome中使用 )。
我已经在ast中构build了pdf并将其stream式传输到浏览器。 我首先用fdf创build它们,然后用自己编写的pdf类创build它们 – 在每种情况下,pdf都是基于通过url传入的几个GET参数从COM对象中检索的数据创build的。
从查看您在ajax调用中收到的数据,看起来就像是在那里。 我还没有玩过几年的代码,并没有logging,以及我一直在关心,但是 – 我认为你所需要做的就是设置一个iframe的目标是url你从中获得pdf。 虽然这可能不起作用 – outout的pdf文件可能还必须outut一个HTML响应标题第一。
简而言之,这是我使用的输出代码:
//We send to a browser header('Content-Type: application/pdf'); if(headers_sent()) $this->Error('Some data has already been output, can\'t send PDF file'); header('Content-Length: '.strlen($this->buffer)); header('Content-Disposition: inline; filename="'.$name.'"'); header('Cache-Control: private, max-age=0, must-revalidate'); header('Pragma: public'); ini_set('zlib.output_compression','0'); echo $this->buffer;
所以,没有看到来自ajax调用的完整响应文本,我不能确定它是什么,尽pipe我倾向于认为输出你要求的pdf的代码可能只是相当于最后一个在上面的代码行。 如果它是代码,你可以控制,我会尝试设置标题 – 这样浏览器可以处理响应文本 – 你不必费心去做一些事情。
我简单地构build了我想要的pdf(时间表)的url,然后创build了一个string,表示所需的sie,id等的iframe的html,它使用构造的url作为src。 只要将div的内部html设置为构造的htmlstring,浏览器就会询问pdf,然后在收到时显示它。
function showPdfTt(studentId) { var url, tgt; title = byId("popupTitle"); title.innerHTML = "Timetable for " + studentId; tgt = byId("popupContent"); url = "pdftimetable.php?"; url += "id="+studentId; url += "&type=Student"; tgt.innerHTML = "<iframe onload=\"centerElem(byId('box'))\" src='"+url+"' width=\"700px\" height=\"500px\"></iframe>"; }
编辑:忘了提及 – 你可以用这种方式发送二进制pdf。 它们包含的stream不需要ascii85或hex编码。 我在pdf中使用了flate,并且工作得很好。
@alexandre与base64的答案是有用的。
为什么这个IE浏览器的解释是在这里
https://en.m.wikipedia.org/wiki/Data_URI_scheme
在标题“格式”下它说
如果同时提供了base64和charset,则某些浏览器(Chrome,Opera,Safari,Firefox)接受非标准sorting,而Internet Explorer则要求charset的规范必须位于base64标记之前。
您可以使用PDF.js从JavaScript创buildPDF文件…这很容易编码…希望这可以解决你的疑问!
问候!
检测浏览器并使用Chrome的Data-URI,并使用其他浏览器的PDF.js。
PDFJS.getDocument(url_of_pdf) .then(function(pdf) { return pdf.getPage(1); }) .then(function(page) { // get a viewport var scale = 1.5; var viewport = page.getViewport(scale); // get or create a canvas var canvas = ...; canvas.width = viewport.width; canvas.height = viewport.height; // render a page page.render({ canvasContext: canvas.getContext('2d'), viewport: viewport }); }) .catch(function(err) { // deal with errors here! });