使用Ajax下载并打开PDF文件

问题描述 投票:95回答:16

我有一个生成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;
   }
}

我通过Ajax调用将其称为action。我不知道将流传输到浏览器的方法。我尝试了几件事,但没有任何效果。

$.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));
    }
});

以上给出错误:

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

javascript java jquery pdf
16个回答
37
投票

您不一定需要为此使用Ajax。如果在服务器端代码中将<a>设置为content-disposition,则仅attachment链接就足够了。这样,如果您最关心的是父页面将保持打开状态(为什么您会为此而不必要地选择Ajax?)。此外,没有办法很好地同步处理这个问题。 PDF不是字符数据。它是二进制数据。您无法执行$(element).load()之类的操作。您想为此使用全新请求。为此,<a href="pdfservlet/filename.pdf">pdf</a>非常合适。

为了为您提供更多服务器端代码方面的帮助,您需要进一步介绍所使用的语言并发布代码尝试的摘录。


2
投票

创建一个隐藏的iframe,然后在上面的ajax代码中:


2
投票

此代码段适用于将面临相同问题的Angular js用户,请注意,响应文件是使用已编程的click事件下载的。在这种情况下,标头是由包含文件名和内容/类型的服务器发送的。


1
投票

您必须使用Ajax吗?可以将它加载到iframe中吗?


1
投票

希望这可以节省您几个小时,并使您免于头痛。我花了一些时间才弄清楚这一点,但是执行常规的$ .ajax()请求破坏了我的PDF文件,而通过地址栏请求它却完美地工作了。解决方案是这样的:


0
投票


0
投票

如果您像我们一样需要处理文件流(因此没有实际保存的PDF),并且您希望下载PDF而无需重新加载页面,则以下功能对我们有效:


0
投票

对于那些希望使用更现代方法的人,可以使用var form = document.getElementById('download-helper-form'); $("#downloadHelperTransferData").val(transferData); form.action = "ServerSideFunctionWhichWritesPdfBytesToResponse"; form.submit(); 。以下示例显示如何下载fetch API文件。使用以下代码即可轻松完成。


116
投票

这是我的工作方式

$.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>")
});

30
投票

我真的不认为过去的任何答案都能找出原始海报的问题。在发布者尝试发布数据并获得响应下载时,他们都假定有GET请求。

在寻找更好的答案的过程中,我们找到了此jQuery Plugin for Requesting Ajax-like File Downloads

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

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

Update与我提到的jQuery插件相比,Mayur的答案看起来非常有前途并且非常简单。


9
投票

这就是我解决此问题的方式。乔纳森·阿曼德(Jonathan Amend)在this post上的回答对我很有帮助。下面的示例已简化。

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

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库的此类。它是可重用的。希望有帮助。


6
投票

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


5
投票

您可以使用此插件来创建表单,然后提交表单,然后将其从页面中删除。


4
投票

要解决发布请求中的空白PDF问题以获取PDF之类的流数据,我们需要在请求中添加响应类型为'arraybuffer'或'blob'


3
投票

关于Mayur Padshala给出的答案,这是通过ajax下载pdf文件的正确逻辑,但正如其他人在评论中报告的那样,该解决方案的确下载了空白的pdf。


3
投票

以下代码为我工作

© www.soinside.com 2019 - 2024. All rights reserved.