Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set a header for a HTTP GET request, and trigger file download?

Update 20140702:

  • The solution
  • Detailed answer as a blog post

(but I'm marking one of the other answers as accepted instead of my own, as it got me halfway there, and to reward the effort)


It appears that setting a HTTP request header is not possible through links with <a href="...">, and can only be done using XMLHttpRequest.

However, the URL linked to is a file that should be downloaded (browser should not navigate to its URL), and I am not sure is this can be done using AJAX.

Additionally, the file being returned is a binary file, and AJAX is not intended for that.

How would one go about triggering a file download with a HTTP request that has a custom header added to it?

edit: fix broken link

like image 415
bguiz Avatar asked Jul 01 '14 01:07

bguiz


2 Answers

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

like image 154
bguiz Avatar answered Sep 30 '22 21:09

bguiz


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

jsfiddle http://jsfiddle.net/guest271314/SJYy3/

like image 28
guest271314 Avatar answered Sep 30 '22 22:09

guest271314