如何使用内容处置强制文件下载到硬盘驱动器?


76

我想强制浏览器下载pdf文件。

我正在使用以下代码:

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

它使浏览器在新窗口中打开pdf,但是我希望在用户单击它时将其下载到硬盘。

我发现它Content-disposition用于此目的,但是在我的情况下该如何使用?


Answers:


122

在要返回PDF文件的HTTP响应上,确保内容处置标头如下所示:

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

请参阅Wikipedia MIME页面上的内容配置


2
@Oded:如果文件是在本地打开的(或者其他任何没有http服务器的情况)
user2284570

@ user2284570-这取决于特定的浏览器和操作系统设置。
Oded 2014年

1
@ user2284570-不知道。看起来很容易在本地测试,不是吗?
Oded 2014年

@Oded:您是否看过我对链接答案的最后评论?该文件未下载为HTML。还有w3schools.com/tags/att_a_download.asp,但我不知道它与JavaScript等效。
user2284570

对我来说非常有用,谢谢,我花了几个小时找出为什么Chrome无法在其查看器中显示pdf文件的问题,问题是我像附件一样在Respose中返回文件。因此,在我要下载响应中的pdf的情况下,我使用了Content-Disposition:附件;为了显示pdf,我使用了Content-Disposition:inline;。非常感谢您的回答。
Alexei Bondarev

13

在最近的浏览器中,您还可以使用HTML5下载属性:

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

除MSIE11之外,大多数最新浏览器均支持该功能。您可以使用polyfill,如下所示(请注意,这仅适用于数据uri,但这是一个不错的开始):

(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
看起来它具有相当好的浏览器支持,但IE 11和移动safari除外:caniuse.com/#feat=download
Stephen Ostermiller

1
@StephenOstermiller最近的浏览器也支持ES7异步/等待和ES6类(MSIE ofc除外)。可以针对MSIE优化公共站点,而可以针对具有新功能的其他浏览器优化管理站点。或者,您可以使用MSIE polyfill。
inf3rno

1
现在已得到广泛支持,但请注意,大多数(所有?)浏览器都适用同源限制。
rymo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.