54

我正在尝试从作为 Ajax 请求响应的二进制流中构建 PDF 文件。

通过XmlHttpRequest我收到以下数据:

%PDF-1.4....
.....
....hole data representing the file
....
%% EOF

到目前为止,我尝试的是通过data:uri. 现在,它没有任何问题,并且工作正常。不幸的是,它在 IE9 和 Firefox 中不起作用。一个可能的原因可能是 FF 和 IE9 在使用data-uri.

现在,我正在寻找适用于所有浏览器的任何解决方案。这是我的代码:

// 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 尚未经过测试)。使用 IE 或 FF 会弹出一个空白的新窗口。

是否有任何解决方案,例如在文件系统上构建 PDF 文件以让用户下载它?我需要适用于所有浏览器的解决方案,至少在 IE、FF、Opera、Chrome 和 Safari 中。

我无权编辑 Web 服务实现。所以它必须是客户端的解决方案。有任何想法吗?

4

8 回答 8

30

是否有任何解决方案,例如在文件系统上构建 pdf 文件以让用户下载它?

尝试设置to ,替换 元素的属性 forresponseType以允许从文件下载响应XMLHttpRequestblobdownloadawindow.openXMLHttpRequest.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();
于 2015-08-01T14:40:11.823 回答
16

我意识到这是一个相当古老的问题,但这是我今天提出的解决方案:

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);
}
于 2016-09-15T16:29:31.613 回答
5

我改变了这个:

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>'; 

它对我有用。

于 2013-02-12T20:07:51.473 回答
3

@alexandre 与 base64 的答案可以解决问题。

为什么这适用于 IE 的解释在这里

https://en.m.wikipedia.org/wiki/Data_URI_scheme

在标题“格式”下它说

如果同时提供 ;base64 和 ;charset ,某些浏览器(Chrome、Opera、Safari、Firefox)接受非标准排序,而 Internet Explorer 要求 charset 的规范必须在 base64 标记之前。

于 2015-07-27T20:00:20.873 回答
2

我在 PHP 中工作并使用一个函数来解码从服务器发回的二进制数据。我将信息提取到一个简单的 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);

?>
于 2013-05-02T19:15:57.317 回答
2

检测浏览器并为 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!
});
于 2015-08-03T13:02:58.830 回答
1

我最近看到了关于这个主题的另一个问题(使用 dataurl 将 pdf 流式传输到 iframe 仅适用于 chrome)。

我已经在 ast 中构建了 pdf 并将它们流式传输到浏览器。我首先使用 fdf 创建它们,然后使用我自己编写的 pdf 类创建它们——在每种情况下,pdf 都是从基于通过 url 传入的几个 GET 参数从 COM 对象检索的数据创建的。

通过查看您在 ajax 调用中收到的发送数据,您似乎就快到了。我已经有几年没有使用代码了,也没有像我想要的那样记录它,但是 - 我认为你需要做的就是将 iframe 的目标设置为 url你从那里得到pdf。虽然这可能不起作用 - 输出 pdf 的文件也可能必须先输出 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 调用的完整响应文本,我无法确定它是什么,尽管我倾向于认为输出您请求的 pdf 的代码可能只相当于最后一个上面代码中的行。如果它是您可以控制的代码,我会尝试设置标题 - 这样浏览器就可以处理响应文本 - 您不必费心对其做任何事情。

我只是为我想要的 pdf 构建了一个 url(一个时间表),然后创建了一个字符串,该字符串表示所需 sie、id 等 iframe 的 html,该 iframe 使用构建的 url 作为它的 src。一旦我将 div 的内部 html 设置为构造的 html 字符串,浏览器就会要求提供 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。它们包含的流不需要是 ascii85 或十六进制编码。我在 pdf 中的所有流上都使用了 flate,效果很好。

于 2012-10-14T00:08:32.933 回答
0

您可以使用PDF.js从 javascript 创建 PDF 文件...它很容易编码...希望这能解决您的疑问!!!

问候!

于 2015-07-28T16:04:23.343 回答