I would like to download and save a file from my browser, using jQuery, in particular an Ajax call.
I found this post: Download File Using Javascript/jQuery and tested the solution provided by Andrew Dunn with the hidden iFrame. In a simple case it works, the server plays well, provides the Content-Disposition: attachment; ... header, I get the Save As pop-up and everything works fine.
However my situation is more complicated: suppose that the request is more than just a simple URL; additional request headers has to be supplied, maybe it is not even a GET method but a POST with some fancy JSON payload. This means that I should be able to "replace" the browser's built-in get page mechanism and provide my AJAX request instead.
For the sake of simplicity let's suppose that I just need to provide a Basic Authentication header with the request. But keep in mind, that I might need more complex requests.
I am not deeply familiar with JavaScript and jQuery, so I was frantically googling around and finally found an almost solution. The idea:
- Add a hidden iframe to the page.
- Add a Form into the frame.
- Define a submit function of the form, that will call my AJAX function, where I can add the required authentication (or any other required header, ...)
- Invoke submit programmatically
Here is the relevant code pieces:
function getFile(url)
{
//Creating the iframe
iframe = document.createElement('iframe');
iframe.id = hiddenIFrameID;
iframe.style.display = 'none';
document.body.appendChild(iframe);
// Adding the form to the frame
var externalHtml = '<form id="downloadForm" action="javascript: void(0);"></form>';
$(document.getElementById(hiddenIFrameID)).contents().find('body').html(externalHtml);
var formObj = $(document.getElementById(hiddenIFrameID));
var form = formObj.contents().find('#downloadForm');
// set the submit action to call my ajax function
form.submit(function () { getURL(url); });
// execute form's submit
form.submit();
}
function getURL(url)
{
var response;
var jqXHR =
$.ajax(
{
type: "GET",
url: url,
async: false,
// authentication, etc
}
);
jqXHR.done( function (data) { response = data;});
return response;
}
As I mentioned, everything almost works! With FireBug I can see, that the request is made, the server replies with 200, sends back the file, the reply has the same Content Disposition header as in the simple case ... But I do not get the Save Us pop-up, the downloaded file just "disappears". BTW, it is not even rendered in the iFrame, for testing I made the frame visible and nothing gets loaded there.
I have a feeling, that something very trivial is missing. Maybe I need to do something with the data returned ... Any idea? I would also appreciate if you have a better approach for this problem.