Wie verwende ich Content-Disposition, um das Herunterladen einer Datei auf die Festplatte zu erzwingen?

76

Ich möchte den Browser zwingen, eine pdfDatei herunterzuladen .

Ich verwende den folgenden Code:

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

Dadurch öffnet der Browser das PDF in einem neuen Fenster, aber ich möchte, dass es auf die Festplatte heruntergeladen wird, wenn ein Benutzer darauf klickt.

Ich habe festgestellt, dass Content-dispositiondies verwendet wird, aber wie verwende ich es in meinem Fall?

Krish
quelle
4
Mögliches Duplikat von Wie implementiere ich Content-Disposition: Anhang?
Quentin

Antworten:

124

Stellen Sie in der HTTP-Antwort, in der Sie die PDF-Datei zurückgeben, sicher, dass der Header für die Inhaltsdisposition wie folgt aussieht:

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

Siehe Inhaltsdisposition auf der Wikipedia MIME-Seite.

Oded
quelle
2
@Oded: Und falls die Datei lokal geöffnet wird (oder in anderen Fällen ohne http-Server) ?
user2284570
@ user2284570 - das würde von bestimmten Browser- und Betriebssystemeinstellungen abhängen.
Oded
1
@ user2284570 - weiß nicht. Sieht einfach genug aus, um vor Ort zu testen, oder?
Oded
@Oded: hast du dir meinen letzten Kommentar zur verlinkten Antwort angesehen? Die Datei wird nicht als HTML heruntergeladen. Es gibt auch w3schools.com/tags/att_a_download.asp , aber ich weiß nicht, ob es JavaScript-Äquivalent ist.
user2284570
Sehr nützlich für mich, danke, ich habe Stunden damit verbracht herauszufinden, warum Chrome keine PDF-Datei in seinem Viewer anzeigt. Das Problem war, dass ich die Datei in Respose wie einen Anhang zurückgebe. In meinem Fall zum Herunterladen eines PDFs in Response habe ich Content-Disposition verwendet: Anhang; und für die Anzeige eines PDFs habe ich Content-Disposition verwendet: inline;. Vielen Dank für Ihre Antwort.
Alexei Bondarev
14

In neueren Browsern können Sie auch das HTML5-Download-Attribut verwenden:

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

Es wird von den meisten aktuellen Browsern mit Ausnahme von MSIE11 unterstützt. Sie können eine Polyfüllung verwenden, etwa so (beachten Sie, dass dies nur für Daten-Uri gilt, dies ist jedoch ein guter Anfang):

(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;
    }
    
})();
inf3rno
quelle
3
Es sieht so aus, als hätte es eine ziemlich gute Browser-Unterstützung außer IE 11 und Mobile Safari: caniuse.com/#feat=download
Stephen Ostermiller
1
@StephenOstermiller Neuere Browser unterstützen auch die ES7-Klassen async / await und ES6 (außer MSIE ofc). Öffentliche Websites können für MSIE optimiert werden, während Verwaltungsseiten für andere Browser mit neuen Funktionen optimiert werden können. Oder Sie können eine MSIE-Polyfüllung verwenden.
inf3rno
1
Wird jetzt weitgehend unterstützt, aber beachten Sie, dass in den meisten (allen?) Browsern eine Einschränkung des gleichen Ursprungs gilt.
Rymo