How to set a header for a HTTP GET request, and trigger file download?
There are two ways to download a file where the HTTP request requires that a header be set.
The credit for the first goes to @guest271314, and credit for the second goes to @dandavis.
The first method is to use the HTML5 File API to create a temporary local file,and the second is to use base64 encoding in conjunction with a data URI.
The solution I used in my project uses the base64 encoding approach for small files, or when the File API is not available,otherwise using the the File API approach.
Solution:
var id = 123; var req = ic.ajax.raw({ type: 'GET', url: '/api/dowloads/'+id, beforeSend: function (request) { request.setRequestHeader('token', 'token for '+id); }, processData: false }); var maxSizeForBase64 = 1048576; //1024 * 1024 req.then( function resolve(result) { var str = result.response; var anchor = $('.vcard-hyperlink'); var windowUrl = window.URL || window.webkitURL; if (str.length > maxSizeForBase64 && typeof windowUrl.createObjectURL === 'function') { var blob = new Blob([result.response], { type: 'text/bin' }); var url = windowUrl.createObjectURL(blob); anchor.prop('href', url); anchor.prop('download', id+'.bin'); anchor.get(0).click(); windowUrl.revokeObjectURL(url); } else { //use base64 encoding when less than set limit or file API is not available anchor.attr({ href: 'data:text/plain;base64,'+FormatUtils.utf8toBase64(result.response), download: id+'.bin', }); anchor.get(0).click(); } }.bind(this), function reject(err) { console.log(err); } );
Note that I'm not using a raw XMLHttpRequest
,and instead using ic-ajax,and should be quite similar to a jQuery.ajax
solution.
Note also that you should substitute text/bin
and .bin
with whatever corresponds to the file type being downloaded.
The implementation of FormatUtils.utf8toBase64
can be found here
Try
html
<!-- placeholder , `click` download , `.remove()` options , at js callback , following js --><a>download</a>
js
$(document).ready(function () { $.ajax({ // `url` url: '/echo/json/', type: "POST", dataType: 'json', // `file`, data-uri, base64 data: { json: JSON.stringify({ "file": "data:text/plain;base64,YWJj" }) }, // `custom header` headers: { "x-custom-header": 123 }, beforeSend: function (jqxhr) { console.log(this.headers); alert("custom headers" + JSON.stringify(this.headers)); }, success: function (data) { // `file download` $("a") .attr({ "href": data.file, "download": "file.txt" }) .html($("a").attr("download")) .get(0).click(); console.log(JSON.parse(JSON.stringify(data))); }, error: function (jqxhr, textStatus, errorThrown) { console.log(textStatus, errorThrown) } }); });
I'm adding another option. The answers above were very useful for me, but I wanted to use jQuery instead of ic-ajax (it seems to have a dependency with Ember when I tried to install through bower). Keep in mind that this solution only works on modern browsers.
In order to implement this on jQuery I used jQuery BinaryTransport. This is a nice plugin to read AJAX responses in binary format.
Then you can do this to download the file and send the headers:
$.ajax({ url: url, type: 'GET', dataType: 'binary', headers: headers, processData: false, success: function(blob) { var windowUrl = window.URL || window.webkitURL; var url = windowUrl.createObjectURL(blob); anchor.prop('href', url); anchor.prop('download', fileName); anchor.get(0).click(); windowUrl.revokeObjectURL(url); }});
The vars in the above script mean:
- url: the URL of the file
- headers: a Javascript object with the headers to send
- fileName: the filename the user will see when downloading the file
- anchor: it is a DOM element that is needed to simulate the download that must be wrapped with jQuery in this case. For example
$('a.download-link')
.