I want to force the browser to download a pdf file.

I am using the following code :

<a href="../doc/quot.pdf" target=_blank>Click here to Download quotation</a>

It makes the browser open the pdf in a new window, but I want it to download to the hard drive when a user clicks it.

I found that Content-disposition is used for this, but how do I use it in my case?

share
1  
How are you controlling the headers? – Oded Feb 8 '12 at 14:36
2  
possible duplicate of How to implement Content-Disposition: attachment? – Quentin Feb 8 '12 at 14:37
up vote 73 down vote accepted

On the HTTP Response where you are returning the PDF file, ensure the content disposition header looks like:

Content-Disposition: attachment; filename=quot.pdf;

See content-disposition on the wikipedia MIME page.

share
4  
i very new to Content-disposition – krish Feb 8 '12 at 14:39
14  
@krish - We all learn somewhere. – Oded Feb 8 '12 at 14:40
    
@Oded : And in case the file is opened locally (or any other cases without an http server)? – user2284570 Sep 6 '14 at 19:30
    
@user2284570 - that would depend on specific browser and OS settings. – Oded Sep 6 '14 at 19:49
    
this is relative to this answer. – user2284570 Sep 6 '14 at 20:10

With recent browsers you can use the HTML5 download attribute as well:

<a download="quot.pdf" href="../doc/quot.pdf">Click here to Download quotation</a>

It is supported by most of the recent browsers except MSIE11. You can use a polyfill, something like this (note that this is for data uri only, but is is a good start):

(function (){

    addEvent(window, "load", function (){
        if (isInternetExplorer())
            polyfillDataUriDownload();
    });

    function polyfillDataUriDownload(){
        var links = document.querySelectorAll('a[download], area[download]');
        for (var index = 0, length = links.length; index<length; ++index) {
            (function (link){
                var dataUri = link.getAttribute("href");
                var fileName = link.getAttribute("download");
                if (dataUri.slice(0,5) != "data:")
                    throw new Error("The XHR part is not implemented here.");
                addEvent(link, "click", function (event){
                    cancelEvent(event);
                    try {
                        var dataBlob = dataUriToBlob(dataUri);
                        forceBlobDownload(dataBlob, fileName);
                    } catch (e) {
                        alert(e)
                    }
                });
            })(links[index]);
        }
    }

    function forceBlobDownload(dataBlob, fileName){
        window.navigator.msSaveBlob(dataBlob, fileName);
    }

    function dataUriToBlob(dataUri) {
        if  (!(/base64/).test(dataUri))
            throw new Error("Supports only base64 encoding.");
        var parts = dataUri.split(/[:;,]/),
            type = parts[1],
            binData = atob(parts.pop()),
            mx = binData.length,
            uiArr = new Uint8Array(mx);
        for(var i = 0; i<mx; ++i)
            uiArr[i] = binData.charCodeAt(i);
        return new Blob([uiArr], {type: type});
    }

    function addEvent(subject, type, listener){
        if (window.addEventListener)
            subject.addEventListener(type, listener, false);
        else if (window.attachEvent)
            subject.attachEvent("on" + type, listener);
    }

    function cancelEvent(event){
        if (event.preventDefault)
            event.preventDefault();
        else
            event.returnValue = false;
    }

    function isInternetExplorer(){
        return /*@cc_on!@*/false || !!document.documentMode;
    }

})();
share
1  
It looks like it has fairly good browser support except IE 11 and mobile safari: caniuse.com/#feat=download – Stephen Ostermiller Apr 20 at 8:46
    
@StephenOstermiller Recent browsers support ES7 async/await and ES6 classes as well (except MSIE ofc.) Public sites can be optimized for MSIE while admin sites can be optimized for other browsers with new features. Or you can use an MSIE polyfill. – inf3rno Apr 20 at 14:42

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.