使用 ajax 请求下载文件

我想发送一个“ ajax 下载请求”时,我点击一个按钮,所以我尝试这种方式:

Javascript:

var xhr = new XMLHttpRequest();
xhr.open("GET", "download.php");
xhr.send();

下载:

<?
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename= file.txt");
header("Content-Transfer-Encoding: binary");
readfile("file.txt");
?>

但是没有达到预期的效果,我该怎么办? 提前谢谢你

385302 次浏览

更新于2015年4月27日

最近出现在 HTML5场景中的是 download attribute。它是 Firefox 和 Chrome 中的 supported,很快就会支持 IE11。根据您的需要,您可以使用它来代替 AJAX 请求(或使用 window.location) ,只要您想要下载的文件与您的站点来源相同。

您可以通过使用 some JavaScript来测试是否支持 download,如果不支持,则将其切换为调用 window.location,从而使 AJAX 请求/window.location成为备用。

原始答案

您不能让一个 AJAX 请求打开下载提示符,因为您必须实际导航到要提示下载的文件。相反,您可以使用一个 Success 函数导航到 download.php。这将打开下载提示符,但不会更改当前页面。

$.ajax({
url: 'download.php',
type: 'POST',
success: function() {
window.location = 'download.php';
}
});

Even though this answers the question, it's better to just use window.location and avoid the AJAX request entirely.

其实你根本不需要 Ajax。如果你只是将“ download.php”设置为按钮上的 href,或者,如果它不是一个链接使用:

window.location = 'download.php';

浏览器应该识别二进制文件下载,而不是加载实际的页面,只是提供文件作为下载。

有可能。您可以从 ajax 函数内部开始下载,例如,在。创建 csv 文件。

I have an ajax function that exports a database of contacts to a .csv file, and just after it finishes, it automatically starts the .csv file download. So, after I get the responseText and everything is Ok, I redirect browser like this:

window.location="download.php?filename=export.csv";

我的 下载文件如下:

<?php


$file = $_GET['filename'];


header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=".$file."");
header("Content-Transfer-Encoding: binary");
header("Content-Type: binary/octet-stream");
readfile($file);


?>

There is no page refresh whatsoever and the file automatically starts downloading.

注意 -在以下浏览器中测试:

Chrome v37.0.2062.120
Firefox v32.0.1
Opera v12.17
Internet Explorer v11

我更喜欢 location.assign(url);

Complete syntax example:

document.location.assign('https://www.urltodocument.com/document.pdf');

Developer.mozilla.org/en-us/docs/web/api/location.assign

要让浏览器下载一个文件,你需要这样请求:

 function downloadFile(urlToSend) {
var req = new XMLHttpRequest();
req.open("GET", urlToSend, true);
req.responseType = "blob";
req.onload = function (event) {
var blob = req.response;
var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download=fileName;
link.click();
};


req.send();
}

Decoding a filename from the header is a little bit more complex...

    var filename = "default.pdf";
var disposition = req.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, '');
}

跨浏览器解决方案,在 Chrome,Firefox,Edge,IE11上测试。

在 DOM 中,添加一个隐藏的 link 标记:

<a id="target" style="display: none"></a>

然后:

var req = new XMLHttpRequest();
req.open("GET", downloadUrl, true);
req.responseType = "blob";
req.setRequestHeader('my-custom-header', 'custom-value'); // adding some headers (if needed)


req.onload = function (event) {
var blob = req.response;
var fileName = null;
var contentType = req.getResponseHeader("content-type");


// IE/EDGE seems not returning some response header
if (req.getResponseHeader("content-disposition")) {
var contentDisposition = req.getResponseHeader("content-disposition");
fileName = contentDisposition.substring(contentDisposition.indexOf("=")+1);
} else {
fileName = "unnamed." + contentType.substring(contentType.indexOf("/")+1);
}


if (window.navigator.msSaveOrOpenBlob) {
// Internet Explorer
window.navigator.msSaveOrOpenBlob(new Blob([blob], {type: contentType}), fileName);
} else {
var el = document.getElementById("target");
el.href = window.URL.createObjectURL(blob);
el.download = fileName;
el.click();
}
};
req.send();

这个解决方案和上面的没有什么不同,但是对我来说,它工作的很好,我认为它是干净的。

我建议使用 base64对文件服务器端(如果使用 PHP,则为 base64 _ encode ())进行编码,并将 base64编码的数据发送给客户机

对客户这样做:

 let blob = this.dataURItoBlob(THE_MIME_TYPE + "," + response.file);
let uri = URL.createObjectURL(blob);
let link = document.createElement("a");
link.download = THE_FILE_NAME,
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);

此代码将编码后的数据放入链接中,并模拟对链接的单击,然后将其删除。

你的需求已经得到了满足 window.location('download.php');
但是我认为你需要传递要下载的文件,而不是总是下载相同的文件,这就是为什么你使用请求,一个选项是创建一个像 showfile.php 一样简单的 php 文件,然后执行一个像

var myfile = filetodownload.txt
var url = "shofile.php?file=" + myfile ;
ajaxRequest.open("GET", url, true);

Showfile.php

<?php
$file = $_GET["file"]
echo $file;

其中的文件是通过获取或发送请求中的文件名传递,然后在函数中捕获响应

if(ajaxRequest.readyState == 4){
var file = ajaxRequest.responseText;
window.location = 'downfile.php?file=' + file;
}
}

下载 Ajax 网页还有另一个解决方案。但是我指的是一个必须首先处理然后下载的页面。

First you need to separate the page processing from the results download.

1)在 ajax 调用中只进行页面计算。

$.post("CalculusPage.php", { calculusFunction: true, ID: 29, data1: "a", data2: "b" },


function(data, status)
{
if (status == "success")
{
/* 2) In the answer the page that uses the previous calculations is downloaded. For example, this can be a page that prints the results of a table calculated in the ajax call. */
window.location.href = DownloadPage.php+"?ID="+29;
}
}
);


// For example: in the CalculusPage.php


if ( !empty($_POST["calculusFunction"]) )
{
$ID = $_POST["ID"];


$query = "INSERT INTO ExamplePage (data1, data2) VALUES ('".$_POST["data1"]."', '".$_POST["data2"]."') WHERE id = ".$ID;
...
}


// For example: in the DownloadPage.php


$ID = $_GET["ID"];


$sede = "SELECT * FROM ExamplePage WHERE id = ".$ID;
...


$filename="Export_Data.xls";
header("Content-Type: application/vnd.ms-excel");
header("Content-Disposition: inline; filename=$filename");


...

我希望这个解决方案对很多人都有用,就像对我一样。

对于那些寻找更现代的方法的人,您可以使用 fetch API。下面的示例演示如何下载电子表格文件。使用下面的代码可以很容易地完成这项工作。

fetch(url, {
body: JSON.stringify(data),
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
})
.then(response => response.blob())
.then(response => {
const blob = new Blob([response], {type: 'application/application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = "file.xlsx";
document.body.appendChild(a);
a.click();
})

I believe this approach to be much easier to understand than other XMLHttpRequest solutions. Also, it has a similar syntax to the jQuery approach, without the need to add any additional libraries.

当然,我建议你检查一下你正在开发的浏览器,因为这种新方法在 IE 上不起作用。您可以在下面的 链接中找到完整的浏览器兼容性列表。

重点 : 在这个示例中,我向监听给定 url的服务器发送一个 JSON 请求。这个 url必须设置,在我的例子,我假设你知道这一部分。此外,还要考虑您的请求工作所需的标头。因为要发送 JSON,所以必须添加 Content-Type头并将其设置为 application/json; charset=utf-8,以便让服务器知道它将接收的请求类型。

@ Joao Marcos 解决方案适合我,但我不得不修改代码,使其在 IE 上工作,如果下面的代码是什么样子

       downloadFile(url,filename) {
var that = this;
const extension =  url.split('/').pop().split('?')[0].split('.').pop();


var req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "blob";
req.onload = function (event) {
const fileName = `${filename}.${extension}`;
const blob = req.response;


if (window.navigator.msSaveBlob) { // IE
window.navigator.msSaveOrOpenBlob(blob, fileName);
}
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
URL.revokeObjectURL(link.href);


};


req.send();
},

这对我有用

var dataObj = {
somekey:"someValue"
}
$.ajax({
method: "POST",
url: "/someController/someMethod",
data: dataObj,
success: function (response) {
const blob = new Blob([response], { type: 'text/csv' });
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = "file.csv";
document.body.appendChild(a);
a.click();
}
});