Download and open PDF file using Ajax

我有一个动作类,生成一个 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));
}
});

上面给出了错误:

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

383617 次浏览

你一定要用 Ajax 做吗? 有没有可能把它加载到 iframe 中?

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

为了更好地帮助您处理服务器端代码,您需要更多地介绍所使用的语言,并发布代码尝试的摘录。

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

网址: document.getElementById('myiframeid').src = your_server_side_url,

移除 window.open(response);

我真的不认为过去的答案中有任何一个指出了原始海报的问题。它们都假定在发帖人试图发布数据并获得响应的下载时发出 GET 请求。

在寻找任何更好的答案的过程中,我们发现了这个 用于请求类 Ajax 文件下载的 jQuery 插件(如果链接在未来某个时候中断,请参阅 互联网档案馆)。

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

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

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

你可以使用这个插件来创建一个表单,并提交它,然后从页面中删除它。

jQuery.download = function(url, data, method) {
//url and data options required
if (url && data) {
//data can be string of parameters or array/object
data = typeof data == 'string' ? data : jQuery.param(data);
//split params into form inputs
var inputs = '';
jQuery.each(data.split('&'), function() {
var pair = this.split('=');
inputs += '<input type="hidden" name="' + pair[0] +
'" value="' + pair[1] + '" />';
});
//send request
jQuery('<form action="' + url +
'" method="' + (method || 'post') + '">' + inputs + '</form>')
.appendTo('body').submit().remove();
};
};




$.download(
'/export.php',
'filename=mySpreadsheet&format=xls&content=' + spreadsheetData
);

这对我很有用,我找到了这个插件 给你

Here is how I got this working

$.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>

Updated answer using download.js

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

这就是我解决问题的方法。
这篇文章上乔纳森 · 阿蒙德的回答对我帮助很大。
下面的例子是简化的。

For more details, the above source code is able to 使用 JQuery Ajax 请求(GET、 POST、 PUT 等)下载文件. It, also, helps to upload parameters as JSON 并将内容类型更改为 application/JSON (我的默认值).

资料来源:

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

一个包含两个输入文本、一个选择和一个按钮元素的简单表单。

The < em > javascript 页 source:

<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 对象。

资料来源:

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();
}
};

I created this class to added to my JS library. It is reusable. Hope that helps.

在服务器函数检索 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();
}
});

var xhr;
var beforeSend = function(){
$('#pleasewaitDL').modal('show');
}
$(function () {
$('#print_brochure_link').click(function(){
beforeSend();
xhr = new XMLHttpRequest();
xhr.open("GET",$('#preparedPrintModalForm').attr('action'), true);
xhr.responseType = "blob";
xhr.onload = function (e) {
if (this.status === 200) {
var file = window.URL.createObjectURL(this.response);
var a = document.createElement("a");
a.href = file;
a.download = this.response.name || "Property Brochure";
console.log(file);
document.body.appendChild(a);
a.click();
                

window.onfocus = function () {
document.body.removeChild(a)
}
$('#pleasewaitDL').modal('hide');
};
};
xhr.send($('#preparedPrintModalForm').serialize());
});
$('#pleasewaitDLCancel').click(function() {
xhr.abort();
});
});

如果你必须像我们一样使用文件流(所以没有实际保存的 PDF 文件) ,并且你想下载 PDF 文件而不需要重新加载页面,以下功能对我们很有用:

HTML

<div id="download-helper-hidden-container" style="display:none">
<form id="download-helper-form" target="pdf-download-output" method="post">
<input type="hidden" name="downloadHelperTransferData" id="downloadHelperTransferData" />
</form>
<iframe id="pdf-helper-output" name="pdf-download-output"></iframe>
</div>

Javascript

var form = document.getElementById('download-helper-form');
$("#downloadHelperTransferData").val(transferData);
form.action = "ServerSideFunctionWhichWritesPdfBytesToResponse";
form.submit();

由于 Target = “ pdf-download-output”的原因,响应被写入 iframe,因此没有执行页面重新加载,但是 pdf-response-stream 在浏览器中作为下载输出。

这个代码片段是为那些将面临同样问题的角度 js 用户准备的,请注意,响应文件是通过一个编程的 click 事件下载的。 在本例中,头由包含文件名和 content/type 的服务器发送。

$http({
method: 'POST',
url: 'DownloadAttachment_URL',
data: { 'fileRef': 'filename.pdf' }, //I'm sending filename as a param
headers: { 'Authorization': $localStorage.jwt === undefined ? jwt : $localStorage.jwt },
responseType: 'arraybuffer',
}).success(function (data, status, headers, config) {
headers = headers();
var filename = headers['x-filename'];
var contentType = headers['content-type'];
var linkElement = document.createElement('a');
try {
var blob = new Blob([data], { type: contentType });
var url = window.URL.createObjectURL(blob);


linkElement.setAttribute('href', url);
linkElement.setAttribute("download", filename);


var clickEvent = new MouseEvent("click", {
"view": window,
"bubbles": true,
"cancelable": false
});
linkElement.dispatchEvent(clickEvent);
} catch (ex) {
console.log(ex);
}
}).error(function (data, status, headers, config) {
}).finally(function () {


});

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

原因可以在 有个问题的公认答案中解释: jQuery 在使用 AJAX 请求加载二进制数据时遇到了一些问题,因为它还没有实现某些 HTML5 XHR v2功能,参见这个增强的 请求和这个 discussion

所以使用 HTMLHTTPRequest的代码应该是这样的:

var req = new XMLHttpRequest();
req.open("POST", "URL", true);
req.responseType = "blob";
req.onload = function (event) {
var blob = req.response;
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="name_for_the_file_to_save_with_extention";
link.click();
}

下面的代码对我很有用

//Parameter to be passed
var data = 'reportid=R3823&isSQL=1&filter=[]';
var xhr = new XMLHttpRequest();
xhr.open("POST", "Reporting.jsp"); //url.It can pdf file path
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.responseType = "blob";
xhr.onload = function () {
if (this.status === 200) {
var blob = new Blob([xhr.response]);
const url = window.URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'myFile.pdf';
a.click();
setTimeout(function () {
// For Firefox it is necessary to delay revoking the ObjectURL
window.URL.revokeObjectURL(data)
, 100
})
}
};
xhr.send(data);

为了修复后请求中的空白 PDF 问题,以获得类似 PDF 的流数据,我们需要在请求中添加响应类型为“ arraybuffer”或“ blob”

$.ajax({
url: '<URL>',
type: "POST",
dataType: 'arraybuffer',
success: function(data) {
let blob = new Blob([data], {type: 'arraybuffer'});
let link = document.createElement('a');
let objectURL = window.URL.createObjectURL(blob);
link.href = objectURL;
link.target = '_self';
link.download = "fileName.pdf";
(document.body || document.documentElement).appendChild(link);
link.click();
setTimeout(()=>{
window.URL.revokeObjectURL(objectURL);
link.remove();
}, 100);
}
});

希望这能帮你节省几个小时,免得你头疼。 It took me a while to figure this out, but doing regular $.ajax() request ruined my PDF file, while requesting it through address bar worked perfectly. 解决办法是这样的:

包括 download.js: http://danml.com/download.html

然后使用 XMLHttpRequest 代替 $. ajax () request。

    var ajax = new XMLHttpRequest();


ajax.open("GET", '/Admin/GetPdf' + id, true);
ajax.onreadystatechange = function(data) {
if (this.readyState == 4)
{
if (this.status == 200)
{
download(this.response, "report.pdf", "application/pdf");


}
else if (this.responseText != "")
{
alert(this.responseText);
}
}
else if (this.readyState == 2)
{
if (this.status == 200)
{
this.responseType = "blob";
}
else
{
this.responseType = "text";
}
}
};


ajax.send(null);

我找到了一个解决方案,为我解决了这个问题(使用 jquery ajax 时为空白 pdf)。我在这里找到了这个神奇的解决方案: https://www.py4u.net/discuss/904599(答案2) ,它涉及到将 XhrFields添加到您的 ajax 调用中:

xhrFields: {
responseType: 'blob'
}

我的例子是:

$.ajax({
url: "myUrl",
type: 'GET',
headers: {"token": mySecurityToken},
xhrFields: {
responseType: 'blob'
},
data: {id: myId}
}).done(function( data, statusText, xhr ) {
var filename = "";
var disposition = xhr.getResponseHeader("Content-Disposition");
if (disposition && (disposition.indexOf("attachment") !== -1) || disposition.indexOf("filename") !== -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([data], {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
}


})

我希望这将解决你们许多人的这个棘手问题。

所有文件类型都100% 正常

// download the file
var link = document.createElement('a'),
filename = fname;
link.href = URL.createObjectURL(data);
link.download = filename;
link.click();

最好的用法是使用提供的链接做一个锚或表单,但是你需要进行验证,或者在其他情况下使用 jquery,最好的用法是添加一个表单并使用 jquery 提交(不要忘记将请求处理设置为服务器端的附件)。

<form id="pdf-form" action="/link_to/download_your.pdf" accept-charset="UTF-8" method="get">
<input type="hidden" name="data" id="data" value="your data"></form>

还有

<a href="javascript:void(0);" id="pdf">Download my Pdf</a>

然后在 jquery 中

$('#pdf').click(function () {
// your data if it json do it like this JSON.stringify(your_data_as_json)
$('#data').val(data);
$('#pdf-form').submit();
})