82

I want to download the file which is coming in the form of bytes from the AJAX response.

I tried to do it this way with the help of Blob:

var blob=new Blob([resultByte], {type: "application/pdf"});
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="myFileName.pdf";
link.click();

It is in fact downloading the pdf file but the file itself is corrupted.

How can I accomplish this?

Ismoil Shokirov
  • 1,114
  • 1
  • 11
  • 25
Jahongir Rahmonov
  • 11,780
  • 8
  • 43
  • 80
  • 3
    This is a bit of a +1 comment. I'm trying to do the same thing, and with the same results - a corrupted PDF. The PDF will open, has the same number of pages I expect, but there is no text. I suspect the issue lies in either the encoding of the PDF, or the conversion of it from `[resultByes]` to a blob... I would like to hear if you came up with a solution. – runlevelsix May 19 '16 at 21:40
  • 1
    @runlevelsix, yes I figured that out! Please see my answer below and see if it works for you too – Jahongir Rahmonov May 20 '16 at 07:39

3 Answers3

177

I asked the question long time ago, so I might be wrong in some details.

It turns out that Blob needs array buffers. That's why base64 bytes need to be converted to array buffers first.

Here is the function to do that:

function base64ToArrayBuffer(base64) {
    var binaryString = window.atob(base64);
    var binaryLen = binaryString.length;
    var bytes = new Uint8Array(binaryLen);
    for (var i = 0; i < binaryLen; i++) {
       var ascii = binaryString.charCodeAt(i);
       bytes[i] = ascii;
    }
    return bytes;
 }

Here is my function to save a pdf file:

function saveByteArray(reportName, byte) {
    var blob = new Blob([byte], {type: "application/pdf"});
    var link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    var fileName = reportName;
    link.download = fileName;
    link.click();
};

Here is how to use these two functions together:

var sampleArr = base64ToArrayBuffer(data);
saveByteArray("Sample Report", sampleArr);
gog
  • 1,070
  • 10
  • 29
Jahongir Rahmonov
  • 11,780
  • 8
  • 43
  • 80
  • 3
    For me, the code is not working in `Firefox 58.0.2`, It executes with no errors, but the download dialog doesn't appear. I need to append the link to `body` and it works. https://bugzilla.mozilla.org/show_bug.cgi?id=1091035 – mihkov Feb 20 '18 at 21:56
  • 1
    I am returning base64 from server side and while use your method it gives me an error : Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded. – Ankita Aug 15 '18 at 07:35
  • To avoid the "failed to execute 'atob' on 'window'" error I had to return the data from my MVC action as JSON (as opposed to a FileResult / FileContentResult) – combatc2 Aug 22 '18 at 12:51
  • I had the same issue and in my case the solution was to assure that I transfer data from the server side to client side in a proper `Base64` format. Once I did it, your solution worked for me. Thanks a lot. – Mike Aug 23 '18 at 14:48
  • 1
    For those with problems with downloads not working in Firefox or IE. Change: link.click() to link.dispatchEvent(new MouseEvent(`click`, {bubbles: true, cancelable: true, view: window})); – bender Nov 23 '18 at 18:15
  • @bender, you left the 'click' without quotes: link.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true, view: window})); – Roy Oliver Dec 20 '18 at 21:30
  • I had to add this line document.body.appendChild(link); after link.href = window.URL.createObjectURL(blob);. Worked perfectly after that! – Dan Leksell Sep 12 '19 at 16:38
  • getting error of "TypeError: base64ToArrayBuffer is not a function" when i called this method to convert bytecode to buffer – s.j Jun 08 '21 at 09:47
  • excellent! I was stuck on converting the Binary String to Byte Array. Thanks for that function! – Gutsygibbon Jul 14 '21 at 16:36
24

You just need to add one extra line and it should work. Your response is byte array from your server application

var bytes = new Uint8Array(resultByte); // pass your byte response to this constructor

var blob=new Blob([bytes], {type: "application/pdf"});// change resultByte to bytes

var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="myFileName.pdf";
link.click();
Bucket
  • 7,139
  • 9
  • 32
  • 45
KrishnaSingh
  • 608
  • 1
  • 6
  • 12
2

Set Blob type at Blob constructor instead of at createObjectURL

var blob = new Blob([resultByte], {type: "application/pdf"});
var link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = "myFileName.pdf";
link.click();
guest271314
  • 1
  • 12
  • 91
  • 170