download file using an ajax request
Solution 1
Update April 27, 2015
Up and coming to the HTML5 scene is the download attribute. It's supported in Firefox and Chrome, and soon to come to IE11. Depending on your needs, you could use it instead of an AJAX request (or using window.location
) so long as the file you want to download is on the same origin as your site.
You could always make the AJAX request/window.location
a fallback by using some JavaScript to test if download
is supported and if not, switching it to call window.location
.
Original answer
You can't have an AJAX request open the download prompt since you physically have to navigate to the file to prompt for download. Instead, you could use a success function to navigate to download.php. This will open the download prompt but won't change the current page.
$.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.
Solution 2
To make the browser downloads a file you need to make the request like that:
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();
}
Solution 3
You actually don't need ajax at all for this. If you just set "download.php" as the href on the button, or, if it's not a link use:
window.location = 'download.php';
The browser should recognise the binary download and not load the actual page but just serve the file as a download.
Solution 4
Cross browser solution, tested on Chrome, Firefox, Edge, IE11.
In the DOM, add an hidden link tag:
<a id="target" style="display: none"></a>
Then:
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();
Solution 5
It is possible. You can have the download started from inside an ajax function, for example, just after the .csv file is created.
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";
My download.php file looks like this:
<?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.
NOTE - Tested in the following browsers:
Chrome v37.0.2062.120
Firefox v32.0.1
Opera v12.17
Internet Explorer v11
Related videos on Youtube
Manuel Di Iorio
Updated on April 17, 2021Comments
-
Manuel Di Iorio about 3 years
I want to send an "ajax download request" when I click on a button, so I tried in this way:
javascript:
var xhr = new XMLHttpRequest(); xhr.open("GET", "download.php"); xhr.send();
download.php:
<? header("Cache-Control: public"); header("Content-Description: File Transfer"); header("Content-Disposition: attachment; filename= file.txt"); header("Content-Transfer-Encoding: binary"); readfile("file.txt"); ?>
but doesn't work as expected, how can I do ? Thank you in advance
-
olegsv over 10 yearsThis will not work, see [this question][1]. [1]: stackoverflow.com/questions/8771342/…
-
Musa over 10 yearsDo
location.href='download.php';
-
Meloman about 7 yearstry this stackoverflow.com/a/42235655/2282880
-
0xc0de over 3 yearsWhen you need this, it does feel like it's a common thing to ask for, and sadly with no elegant solutions.
-
-
mikemaccana about 10 yearsThe programming language you're using to change
window.location
is JavaScript. -
Jelle Kralt about 10 yearsYou're right @mikemaccana, I actually meant ajax :).
-
Gustavo Straube over 9 yearsAs @ManuelDiIorio said, a simple
window.location
resolves the question. So I think the reply from Jelle Kralt below answers better the question. -
user1447679 about 9 yearsDoesn't this call the link twice? I'm in a similar boat... I'm passing a lot of security information in headers, and able to parse the file object in the success function, but don't know how to trigger a download prompt.
-
mmmmmm about 8 yearsIt does call the page twice, so if you are querying a database in that page, this means 2 trips to DB.
-
Yangshun Tay almost 8 yearsHave been hunting high and low for a solution and this is so elegant and perfect. Thank you so much.
-
Mickael Bergeron Néron almost 8 yearsIsn't this dangerous security-wise?
-
Pedro Sousa almost 8 years@MickaelBergeronNéron Why?
-
Mickael Bergeron Néron almost 8 yearsI would think so because anybody can call download.php?filename=[something] and try some path and file names, especially common ones, and this could even be done inside a loop within a program or a script.
-
Pedro Sousa almost 8 yearswouldn't .htaccess avoid that?
-
Prof almost 8 years@PedroSousa .. no. htaccess controls access to the file structure via Apache. Since the access has reached a PHP script, htaccess now stops its duty. This IS VERY MUCH a security hole because indeed, any file that PHP (and the user it is being run under) can read, so it can deliver into the readfile... One should always sanitise the requested file to be read
-
Pedro Sousa almost 8 years@prof83 I guess you are right. For the sake of security, we should always sanitise files to be requested. Thanks for poiting it out, i will definitely have that into account in the future. Thanks :)
-
John almost 8 years@user1447679 see for an alternative solution: stackoverflow.com/questions/38665947/…
-
mickmackusa about 7 yearsPlease format your entire code block and provide some additional explanation to your process for future reader benefit.
-
Erik Donohoo almost 7 yearsThis works for me, but in firefox, I needed to first put an <a> tag in the DOM, and reference it as my link rather than create one on the fly in order for the file to download automatically.
-
Diego almost 7 yearsworks but what happens if the file is creating during execution? it doesnt work like when the file is created already.
-
Scott almost 7 yearsLet me explain how this helped me... the example could have been more complete. with "download.php?get_file=true" or something... I have an ajax function that does some error checking on a form submission and then creates a csv file. If the error check fails, it has to come back with why it failed. If it creates the CSV it is telling the parent that "go ahead and fetch the file". I do that by posting to the ajax file with the form variable then posting a DIFFERENT parameter to the same file saying "hand me the file you just created" (path/name is hard coded into the ajax file).
-
krillgar over 6 yearsOf course, this solution will only work if it is a static file that already exists.
-
Dharmendrasinh Chudasama about 6 yearsBut it will send request 2 times, that is not proper
-
Ian almost 6 yearsIf the server responds with an error though there won't be any way to stay on your main page without being redirected to an error page by the browser. At least this is what Chrome does when the result of window.location returns 404.
-
JSG almost 6 yearsDownloading period is dangerous. Using a token system or some sort of download management is required for all answers here to keep them safe. These worries are valid for every one of them that doesn't have the security/management.
-
Steve Owens over 5 yearsSo I see some comments where there is complaint that this is not useful but that is not always the case. Consider an S3 presigned url with customer provided keys on encryption. You still have to provide custom headers on the get to download the object so simply setting window.locaion = signedurl will not work you need to send the encryption key and other info in custom AWS specific headers so this is worthy of an upvote.
-
BPeela about 5 yearsYou can just make the a tag hidden and populate the href dynamically. no need to add and remove
-
Sнаđошƒаӽ about 5 years@Taha I tested this on Edge and it seemed to work. Don't know about IE though. My client doesn't target IE users ;-) Am I lucky? :D
-
Márton Tamás almost 5 years@ErikDonohoo You can create the
<a>
tag with JS, "on the fly" as well, but gotta append it todocument.body
. You certainly want to hide it at the same time. -
Gonzalo De-Spirito almost 5 yearsThis is a bad idea. it call the url twice. It makes no sense at all. Why dont you execulte window.location = 'download.php' without the ajax overhead?
-
vibs2006 over 4 yearsGood Generic Code. @leo can you improve this code by adding custom headers like
Authorization
? -
vibs2006 over 4 yearsThanks @leo. Its helpful.Also what do you suggest adding
window.URL.revokeObjectURL(el.href);
afterel.click()
? -
Abhishek Gharai over 4 yearsThanks @João, I was looking for this solution from a very long time.
-
Mathew Alden almost 4 yearsThe filename will be wrong if the content disposition specifies a non-UTF8 filename.
-
CJ Broersma almost 3 yearswow I overthought it. I just added my file name as a GET param and bingo. Thanks!
-
Hughsie28 over 2 yearsSeveral years later and its still not supported in IE11, sad times.