使用 Ajax 下载并打开 PDF 文件

IT技术 javascript java jquery pdf
2021-01-12 19:14:49

我有一个生成 PDF 的操作类。contentType适当地设定。

public class MyAction extends ActionSupport 
{
   public String execute() {
    ...
    ...
    File report = signedPdfExporter.generateReport(xyzData, props);

    inputStream = new FileInputStream(report);
    contentDisposition = "attachment=\"" + report.getName() + "\"";
    contentType = "application/pdf";
    return SUCCESS;
   }
}

action 通过 Ajax 调用来调用它。我不知道如何将此流传送到浏览器。我尝试了几件事,但没有任何效果。

$.ajax({
    type: "POST",
    url: url,
    data: wireIdList,
    cache: false,
    success: function(response)
    {
        alert('got response');
        window.open(response);
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) 
    {
        alert('Error occurred while opening fax template' 
              + getAjaxErrorString(textStatus, errorThrown));
    }
});

以上给出了错误:

您的浏览器发送了此服务器无法理解的请求。

6个回答

这是我如何工作的

$.ajax({
  url: '<URL_TO_FILE>',
  success: function(data) {
    var blob=new Blob([data]);
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="<FILENAME_TO_SAVE_WITH_EXTENSION>";
    link.click();
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

使用download.js更新答案

$.ajax({
  url: '<URL_TO_FILE>',
  success: download.bind(true, "<FILENAME_TO_SAVE_WITH_EXTENSION>", "<FILE_MIME_TYPE>")
});

这个(锚元素)实际上在 IE 11、Edge 和 Firefox 上对我不起作用。将成功更改为仅使用“window.open(URL.createObjectURL(blob))”确实有效。
2021-03-18 19:14:49
pdf 文件已下载,但没有内容可用。我在服务器端保存了 byte[] 并且 pdf 内容可用。请建议。
2021-03-18 19:14:49
是的,它确实适用于所有现代浏览器。如果您看到空白的 pdf,请尝试在新选项卡中运行 ajax url。如果那里也出现空白屏幕,则可能是 pdf 本身存在问题。如果您确实在那里看到了 pdf 文件而不是在下载的文件中,请在我的电子邮件中告诉我。:)
2021-03-21 19:14:49
它适用于 chrome 吗?我只能看到一个空白的pdf。
2021-04-07 19:14:49
下载空白 pdf 文件。
2021-04-10 19:14:49

为此,您不一定需要 Ajax。<a>如果您在服务器端代码中设置content-dispositionto attachment只需一个链接就足够了。这样父页面将保持打开状态,如果这是您的主要关注点(否则为什么您会不必要地为此选择 Ajax?)。此外,没有办法很好地异步处理这个问题。PDF 不是字符数据。是二进制数据。你不能做这样的事情$(element).load()您想为此使用全新的请求。因为那<a href="pdfservlet/filename.pdf">pdf</a>是完全合适的。

为了在服务器端代码方面为您提供更多帮助,您需要详细说明所使用的语言并发布代码尝试的摘录。

再次:你并不需要的Ajax这一点。这只是自找麻烦。PDF 是二进制数据,而不是像 HTML 或 JSON 那样的字符数据。
2021-03-15 19:14:49
同意@EdwardOlamisan,这不是一个正确的答案,因为作者试图POST数据。
2021-03-26 19:14:49
在某些浏览器中,window.open 将保持打开和空白状态,这对最终用户来说可能很烦人。因此,也不要为此使用 window.open。如果content-disposition设置为attachment,您将只获得Save as对话。父页面将保持不变。Just <a href="pdfservlet/filename.pdf">pdf</a>or a<form action="pdfservlet/filename.pdf"><input type="submit"></form>已经绰绰有余了。
2021-04-03 19:14:49
var url = contextPath + "/xyz/blahBlah.action"; 网址+=网址+“?” + 参数;尝试 { var child = window.open(url); child.focus(); } 赶上 (e) { }
2021-04-08 19:14:49
Url 长度有限制。作者正在询问 POST。
2021-04-08 19:14:49

我真的认为过去的任何答案都没有发现原始海报的问题。当发布者尝试 POST 数据并获取下载作为响应时,它们都假定一个 GET 请求。

在寻找任何更好的答案的过程中,我们发现了这个用于请求类似 Ajax 的文件下载的 jQuery 插件

在它的“核心”中,它创建了一个包含给定数据作为输入字段的“临时”HTML 表单。此表单将附加到文档并发布到所需的 URL。紧接着,表单再次被删除:

jQuery('<form action="'+ url +'" method="'+ (method||'post') +'">'+inputs+'</form>')
    .appendTo('body').submit().remove()

与我提到的 jQuery 插件相比,更新Mayur 的答案看起来非常有希望并且非常简单。

这就是我解决这个问题的方法。
Jonathan Amend 在这篇文章中的回答对我帮助很大。
下面的例子是简化的。

有关更多详细信息,上述源代码能够使用 JQuery Ajax 请求(GET、POST、PUT 等)下载文件它还有助于将参数上传为JSON 并将内容类型更改为 application/json (my default)

HTML源:

<form method="POST">
    <input type="text" name="startDate"/>
    <input type="text" name="endDate"/>
    <input type="text" name="startDate"/>
    <select name="reportTimeDetail">
        <option value="1">1</option>
    </select>
    <button type="submit"> Submit</button>
</form>  

一个简单的表单,有两个输入文本,一个选择和一个按钮元素。

JavaScript的网页来源:

<script type="text/javascript" src="JQuery 1.11.0 link"></script>
<script type="text/javascript">
    // File Download on form submition.
    $(document).on("ready", function(){
        $("form button").on("click", function (event) {
            event.stopPropagation(); // Do not propagate the event.

            // Create an object that will manage to download the file.
            new AjaxDownloadFile({
                url: "url that returns a file",
                data: JSON.stringify($("form").serializeObject())
            });

            return false; // Do not submit the form.
        });
    });
</script>  

一个简单的按钮点击事件。它创建了一个 AjaxDownloadFile 对象。AjaxDownloadFile 类源代码如下。

AjaxDownloadFile类来源:

var AjaxDownloadFile = function (configurationSettings) {
    // Standard settings.
    this.settings = {
        // JQuery AJAX default attributes.
        url: "",
        type: "POST",
        headers: {
            "Content-Type": "application/json; charset=UTF-8"
        },
        data: {},
        // Custom events.
        onSuccessStart: function (response, status, xhr, self) {
        },
        onSuccessFinish: function (response, status, xhr, self, filename) {
        },
        onErrorOccured: function (response, status, xhr, self) {
        }
    };
    this.download = function () {
        var self = this;
        $.ajax({
            type: this.settings.type,
            url: this.settings.url,
            headers: this.settings.headers,
            data: this.settings.data,
            success: function (response, status, xhr) {
                // Start custom event.
                self.settings.onSuccessStart(response, status, xhr, self);

                // Check if a filename is existing on the response headers.
                var filename = "";
                var disposition = xhr.getResponseHeader("Content-Disposition");
                if (disposition && disposition.indexOf("attachment") !== -1) {
                    var filenameRegex = /filename[^;=\n]*=(([""]).*?\2|[^;\n]*)/;
                    var matches = filenameRegex.exec(disposition);
                    if (matches != null && matches[1])
                        filename = matches[1].replace(/[""]/g, "");
                }

                var type = xhr.getResponseHeader("Content-Type");
                var blob = new Blob([response], {type: type});

                if (typeof window.navigator.msSaveBlob !== "undefined") {
                    // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed.
                    window.navigator.msSaveBlob(blob, filename);
                } else {
                    var URL = window.URL || window.webkitURL;
                    var downloadUrl = URL.createObjectURL(blob);

                    if (filename) {
                        // Use HTML5 a[download] attribute to specify filename.
                        var a = document.createElement("a");
                        // Safari doesn"t support this yet.
                        if (typeof a.download === "undefined") {
                            window.location = downloadUrl;
                        } else {
                            a.href = downloadUrl;
                            a.download = filename;
                            document.body.appendChild(a);
                            a.click();
                        }
                    } else {
                        window.location = downloadUrl;
                    }

                    setTimeout(function () {
                        URL.revokeObjectURL(downloadUrl);
                    }, 100); // Cleanup
                }

                // Final custom event.
                self.settings.onSuccessFinish(response, status, xhr, self, filename);
            },
            error: function (response, status, xhr) {
                // Custom event to handle the error.
                self.settings.onErrorOccured(response, status, xhr, self);
            }
        });
    };
    // Constructor.
    {
        // Merge settings.
        $.extend(this.settings, configurationSettings);
        // Make the request.
        this.download();
    }
};

我创建了这个类来添加到我的 JS 库中。它是可重复使用的。希望有帮助。

这是一个很好的答案,但出于某种原因,我只是不断地损坏空的 PDF。想不通 当我通过 API 返回相同的字节集时 - 很好,所以这与 MVC 响应有关。我使用 FileResult 响应类型: File(bytes, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
2021-03-12 19:14:49
我有完全相同的问题。所有回答“只是让它成为一个链接”的人都没有帮助 OP。如果您的内容是动态的,并且您要访问的链接是动态的,则您必须对其全部进行 jquery ......我的答案是在页面上放置一个包含所有隐藏输入的表单(不向用户显示)和然后填写并用jquery提交。效果很好。
2021-03-15 19:14:49
Blob IE10+ 支持对象。
2021-03-19 19:14:49
我必须将responseTypexhr设置arraybufferblob才能使其工作。(否则,这很好用。)
2021-03-29 19:14:49
说明:如果通过地址栏打开 URL - 文件已正确打开。如果我使用 AJAX + blob 来获取文件 - 文件格式错误。
2021-04-03 19:14:49

对我有用的是以下代码,因为服务器功能正在检索 File(memoryStream.GetBuffer(), "application/pdf", "fileName.pdf");:

$http.get( fullUrl, { responseType: 'arraybuffer' })
            .success(function (response) {
                var blob = new Blob([response], { type: 'application/pdf' });

                if (window.navigator && window.navigator.msSaveOrOpenBlob) {
                    window.navigator.msSaveOrOpenBlob(blob); // for IE
                }
                else {
                    var fileURL = URL.createObjectURL(blob);
                    var newWin = window.open(fileURL);
                    newWin.focus();
                    newWin.reload();
                }
});
在发表此评论和最新的 Chrome 时,这对我来说非常有效
2021-04-05 19:14:49