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?


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.


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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.