2012-02-08 18 views
48

Quiero obligar al navegador a descargar un archivo pdf.Cómo usar Content-disposition para forzar la descarga de un archivo en el disco duro?

estoy usando el siguiente código:

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

Esto hace que el navegador abra el PDF en una nueva ventana, pero quiero que se descargue en el disco duro cuando un usuario hace clic en él.

Encontré que Content-disposition se usa para esto, pero ¿cómo lo uso en mi caso?

+1

¿Cómo está controlando los encabezados? – Oded

+2

posible duplicado de [Cómo implementar Content-Disposition: attachment?] (Http://stackoverflow.com/questions/8875949/how-to-implement-conposition-disposition-attachment) – Quentin

Respuesta

83

En la respuesta HTTP, donde va a devolver el archivo PDF, garantizar el encabezado de disposición de contenido se ve como:

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

Ver content-disposition en la página de Wikipedia MIME.

+6

soy muy nuevo en Content-disposition – krish

+21

@ Krish - Todos aprendemos en algún lado. – Oded

+0

@Oded: ¿Y en caso de que el archivo se abra localmente * (o en cualquier otro caso sin un servidor http) *? – user2284570

4

Con navegadores actuales puede utilizar el atributo de descarga HTML5 así:

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

Es apoyado por la mayor parte de los últimos navegadores excepto MSIE11. Puede usar un polyfill, algo como esto (tenga en cuenta que esto es solo para datos uri, pero es un buen comienzo):

(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 /*@[email protected]*/false || !!document.documentMode; 
    } 

})(); 
+1

Parece que tiene bastante buena compatibilidad con el navegador excepto IE 11 y safari móvil: http://caniuse.com/#feat=download –

+0

@StephenOstermiller Los navegadores recientes también admiten ES7 async/await y clases ES6 (excepto la versión de MSIE). Los sitios públicos se pueden optimizar para MSIE, mientras que los sitios de administración se pueden optimizar para otros navegadores con nuevas funciones. O puede usar un polyfill de MSIE. – inf3rno

Cuestiones relacionadas