47

I want to download a pdf file for jquery ajax response. Ajax response contains pdf file data. I tried this solution. My code is given below but I always get a blank pdf.

$(document).on('click', '.download-ss-btn', function () {

    $.ajax({
        type: "POST",
        url: 'http://127.0.0.1:8080/utils/json/pdfGen',
        data: {
            data: JSON.stringify(jsonData)
        }

    }).done(function (data) {
        var blob = new Blob([data]);
        var link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = "Sample.pdf";
        link.click();
    });


});
Community
  • 1
  • 1
azhar
  • 1,709
  • 1
  • 19
  • 41
  • Try substituting `XMLHttpRequest` for `jQuery.ajax()` see http://stackoverflow.com/questions/12876000/how-to-build-pdf-file-from-binary-string-returned-from-a-web-service-using-javas – guest271314 Jan 04 '16 at 07:45
  • 2
    Why do you need to use AJAX for this? Downloading files is much more easily and reliably done without it. – Darin Dimitrov Jan 04 '16 at 07:57
  • You can not make pdf with `json` response.It should be a `HTML` response and also it dosn't work on all browser. In given ex. it returns `Url` means a HTML response. – Parth Trivedi Jan 04 '16 at 08:00
  • 1
    Here i am using a web service to get formatted pdf file for json data. the response pdf file data start with `%PDF-1.4` – azhar Jan 04 '16 at 08:08
  • You have to write code in `success` then `.done` and in which `browser` version you are testing. ` Blob([data])` not working in some browser. – Parth Trivedi Jan 04 '16 at 08:11
  • when i console the data from the ajax response i get the file data properly. – azhar Jan 04 '16 at 08:28

5 Answers5

107

jQuery has some issues loading binary data using AJAX requests, as it does not yet implement some HTML5 XHR v2 capabilities, see this enhancement request and this discussion

Given that, you have one of two solutions:

First solution, abandon JQuery and use XMLHTTPRequest

Go with the native HTMLHTTPRequest, here is the code to do what you need

  var req = new XMLHttpRequest();
  req.open("GET", "/file.pdf", true);
  req.responseType = "blob";

  req.onload = function (event) {
    var blob = req.response;
    console.log(blob.size);
    var link=document.createElement('a');
    link.href=window.URL.createObjectURL(blob);
    link.download="Dossier_" + new Date() + ".pdf";
    link.click();
  };

  req.send();

Second solution, use the jquery-ajax-native plugin

The plugin can be found here and can be used to the XHR V2 capabilities missing in JQuery, here is a sample code how to use it

$.ajax({
  dataType: 'native',
  url: "/file.pdf",
  xhrFields: {
    responseType: 'blob'
  },
  success: function(blob){
    console.log(blob.size);
      var link=document.createElement('a');
      link.href=window.URL.createObjectURL(blob);
      link.download="Dossier_" + new Date() + ".pdf";
      link.click();
  }
});
Hisham
  • 2,586
  • 1
  • 14
  • 18
  • 8
    To make it work in Firefox you have to add 'document.body.appendChild(link);' before clicking the link :) – Arnaud Rochez Jun 08 '17 at 11:24
  • 1
    Works nicely but I found you will need window.navigator.msSaveBlob(blob, filename); to get this working in IE11 as shown by @anonymous. – Perry Mar 21 '18 at 16:22
  • Thank you so much! – Marcia Ong Jan 30 '19 at 07:33
  • This is exactly what I needed. xhrFields: { responseType: 'blob' }, – sho Feb 11 '19 at 23:43
  • 1
    InvalidStateError: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was 'blob'). – Ryan Dooley Jun 18 '19 at 14:24
  • The first solution worked for me. I have a potential issue with the PDFs though, apparently won't work in Windows Explorer Preview once downloaded, not sure why - but probably a different problem. – Craig Lambie Jan 07 '20 at 08:37
  • `Uncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.` on Chrome – Arun Jul 25 '20 at 15:34
  • The first solution worked for me but after downloading the pdf file when I try to open the file it gives me an error saying that 'Adobe Acrobat Reader could not open... because it is either not a supported file blah blah....' – Waseem Dec 30 '21 at 11:35
22

I am newbie and most of the code is from google search. I got my pdf download working with the code below (trial and error play). Thank you for code tips (xhrFields) above.

$.ajax({
            cache: false,
            type: 'POST',
            url: 'yourURL',
            contentType: false,
            processData: false,
            data: yourdata,
             //xhrFields is what did the trick to read the blob to pdf
            xhrFields: {
                responseType: 'blob'
            },
            success: function (response, status, xhr) {

                var filename = "";                   
                var disposition = xhr.getResponseHeader('Content-Disposition');

                 if (disposition) {
                    var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                    var matches = filenameRegex.exec(disposition);
                    if (matches !== null && matches[1]) filename = matches[1].replace(/['"]/g, '');
                } 
                var linkelem = document.createElement('a');
                try {
                                           var blob = new Blob([response], { type: 'application/octet-stream' });                        

                    if (typeof window.navigator.msSaveBlob !== 'undefined') {
                        //   IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
                        window.navigator.msSaveBlob(blob, filename);
                    } else {
                        var URL = window.URL || window.webkitURL;
                        var downloadUrl = URL.createObjectURL(blob);

                        if (filename) { 
                            // use HTML5 a[download] attribute to specify filename
                            var a = document.createElement("a");

                            // safari doesn't support this yet
                            if (typeof a.download === 'undefined') {
                                window.location = downloadUrl;
                            } else {
                                a.href = downloadUrl;
                                a.download = filename;
                                document.body.appendChild(a);
                                a.target = "_blank";
                                a.click();
                            }
                        } else {
                            window.location = downloadUrl;
                        }
                    }   

                } catch (ex) {
                    console.log(ex);
                } 
            }
        });
BSMP
  • 4,596
  • 8
  • 33
  • 44
anonymous
  • 221
  • 2
  • 2
7

You can do this with html5 very easily:

var link = document.createElement('a');
link.href = "/WWW/test.pdf";
link.download = "file_" + new Date() + ".pdf";
link.click();
link.remove();
Luca Ziegler
  • 3,236
  • 1
  • 22
  • 39
5

For those looking a more modern approach, you can use the fetch API. The following example shows how to download a PDF file. It is easily done with the following code.

fetch(url, {
    body: JSON.stringify(data),
    method: 'POST',
    headers: {
        'Content-Type': 'application/json; charset=utf-8'
    },
})
.then(response => response.blob())
.then(response => {
    const blob = new Blob([response], {type: 'application/pdf'});
    const downloadUrl = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = downloadUrl;
    a.download = "file.pdf";
    document.body.appendChild(a);
    a.click();
})

I believe this approach to be much easier to understand than other XMLHttpRequest solutions. Also, it has a similar syntax to the jQuery approach, without the need to add any additional libraries.

Of course, I would advise checking to which browser you are developing, since this new approach won't work on IE. You can find the full browser compatibility list on the following [link][1].

Important: In this example I am sending a JSON request to a server listening on the given url. This url must be set, on my example I am assuming you know this part. Also, consider the headers needed for your request to work. Since I am sending a JSON, I must add the Content-Type header and set it to application/json; charset=utf-8, as to let the server know the type of request it will receive.

Alain Cruz
  • 4,757
  • 3
  • 25
  • 43
0

Try this:

$(document).on('click', '.download-ss-btn', function () {

    $.ajax({
        type: "POST",
        url: 'http://127.0.0.1:8080/utils/json/pdfGen',
        data: {
            data: JSON.stringify(jsonData)
        },
        headers: {
            'Content-Type': 'application/json; charset=utf-8'
        }

    }).done(function (data) {
        let binaryString = window.atob(data);
        let binaryLen = binaryString.length;
        let bytes = new Uint8Array(binaryLen);

        for (let i = 0; i < binaryLen; i++) {
            let ascii = binaryString.charCodeAt(i);
            bytes[i] = ascii;
        }
        var blob = new Blob([data], {type: "application/pdf"});
        var link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = "Sample.pdf";
        link.click();
    });
});
zean_7
  • 336
  • 3
  • 12