(HTML) Descargue un archivo PDF en lugar de abrirlo en el navegador al hacer clic

115

Me preguntaba cómo hacer que el enlace de un archivo PDF se pueda descargar en lugar de abrirlo en el navegador. ¿Cómo se hace esto en html? (Asumiría que se hace a través de javascript o algo así).

error 404
fuente
3
Que yo sepa, esto no es un comportamiento programable. La mayoría de los navegadores tendrán sus propias configuraciones para el comportamiento de qué hacer con tipos de archivos específicos durante la descarga.
Bart
1
A partir de HTML5, el OP debería actualizar la respuesta correcta a la respuesta de Sarim.
Omar Tariq
posible duplicado de Force para abrir la ventana emergente "Guardar como ..." abierta en el enlace de texto haga clic para PDF en HTML
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Esta pregunta también ha sido respondida aquí: stackoverflow.com/a/30714824/847235
intrepidis

Respuestas:

38

No puede hacer esto con HTML. Es una solución basada en servidor. Debe transmitir el archivo para que el navegador active el cuadro de diálogo para guardar.

Aconsejaría no hacer esto. La forma en que un usuario interactúa con un PDF debe dejarse en manos del usuario.

ACTUALIZACIÓN (2014):

Entonces ... esta respuesta todavía recibe muchos votos negativos. Supongo que parte de eso es que esto se respondió hace 4 años y, como señala Sarim, ahora existe el atributo HTML 5download que puede manejar esto.

Estoy de acuerdo y creo que la respuesta de Sarim es buena (probablemente debería ser la respuesta elegida si el OP regresa). Sin embargo, esta respuesta sigue siendo la forma confiable de manejarlo (como señala la respuesta de Yiğit Yener y, curiosamente, la gente está de acuerdo). Si bien el atributo de descarga ha ganado soporte, sigue siendo irregular:

http://caniuse.com/#feat=download

DA.
fuente
18
Sé que tiene un año, pero no estoy de acuerdo. Hay circunstancias en las que forzar este comportamiento es muy importante para el flujo de la aplicación. La respuesta real es establecer la disposición de contenido en el encabezado para que sea "adjunto" en lugar de "en línea".
user158017
9
Estoy de acuerdo en que, en otras circunstancias, es mejor dejarlo en manos del usuario. Sin embargo, llegué a este hilo en busca de una respuesta, y la "respuesta" marcada no era una respuesta, era "no deberías hacer eso". Para mí, esa no es una respuesta a la pregunta. En su lugar, da una respuesta específica y también aconsejar.
user158017
1
A veces la pregunta es incorrecta. ;) De todos modos, con respecto a su problema, todo es un problema de UX. Obligar a la web a comportarse de maneras específicas a veces es necesario, pero a menudo hay mejores soluciones desde una perspectiva de UX. Además, mi respuesta es correcta. No puede hacer lo que quiere hacer con HTML (que es lo que hacía la pregunta). Es una solución del lado del servidor.
DA.
1
Esta es una de mis respuestas más extrañas que he publicado. La gente todavía encuentra su camino aquí para rechazarlo. ¡Lo cual está bien! Pero sería interesante saber por qué.
DA.
3
Acerca de esa votación negativa, puede ser la caída de la civilización lo fácil que es parecer involuntariamente arrogante en el texto. Esta respuesta me parece tan larga en opiniones condescendientes y corta en respuestas. En lugar del párrafo 1, simplemente agregue la httpetiqueta a la pregunta. En lugar del párrafo 2: "Es posible que desee reconsiderar si evitar la visualización inmediata de PDF es lo mejor para los usuarios. Habiendo dicho eso ..." Entonces asuma que el OP y los futuros lectores son adultos y continúe con una respuesta procesable como la de Yener .
Bob Stein
133

Con html5, ahora es posible. Establezca un elemento de atributo "descargar".

<a href="http://link/to/file" download="FileName">Download it!</a>

Fuente: http://updates.html5rocks.com/2011/08/Downloading-resources-in-HTML5-a-download

Sarim
fuente
Será mejor que elija esta solución si es compatible. Aquí hay una forma de verificar si lo esif ("download" in document.createElement("a")){ ... }
pmrotule
Agregué otra respuesta a continuación (aunque mal truco), aunque esta sigue siendo la forma preferida, tal vez la forma de pirateo podría ofrecerse para navegadores no compatibles.
Sarim
¿Hay alguna manera de especificar el texto del pdf en lugar de mencionar la ruta del archivo? Necesito crear pdf a partir de un div html pero no deseo abrir otra ventana, la descarga debería ser parecida a la de esta respuesta ..
T.Adak
1
Al igual que en agosto de 2019, la compatibilidad con el navegador parece estar mejorada para esta función, consulte: w3schools.com/tags/att_a_download.asp
Daniel Resch
2
Tenga en cuenta que el atributo de descarga solo se admite para solicitudes del mismo origen.
Quentin
82

Esto solo es posible con la configuración de un encabezado de respuesta http mediante el código del lado del servidor. A saber;

Content-Disposition: attachment; filename=fname.ext
Yiğit Yener
fuente
2
esta es la respuesta perfecta, simplemente encuentre la manera de hacerlo en el lenguaje apropiado del lado del servidor.
user158017
Ejemplo de Apache . Ejemplo de matraz .
Bob Stein
Desafortunadamente, iOS seguirá obteniendo una vista previa y no descargará archivos PDF, incluso si la disposición del contenido es 'adjunto'.
Jorn van de Beek
14

Necesita cambiar los encabezados http enviados. Dependiendo de su servidor, puede modificar su .htaccess de la siguiente manera:

<FilesMatch "\.(?i:pdf)$">
  ForceType application/octet-stream
  Header set Content-Disposition attachment
</FilesMatch>
chico php
fuente
No es necesario mentir sobre el tipo de contenido. Establecer la disposición del contenido es suficiente.
Quentin
9

necesitará usar un script PHP (u otro lenguaje del lado del servidor para esto)

<?php
// We'll be outputting a PDF
header('Content-type: application/pdf');

// It will be called downloaded.pdf
header('Content-Disposition: attachment; filename="downloaded.pdf"');

// The PDF source is in original.pdf
readfile('original.pdf');
?>

y use httacces para redirigir (reescribir) al archivo PHP en lugar del pdf

código de barba
fuente
Hmm, funciona muy bien cuando abro el archivo php directamente. Pero cuando trato de usar la redirección, como aquí: Redirect 301 /_PDFs/Catalogue.pdf http://www.example.com/_PDFs/___download_the_catalogue_instead_opening.phpe intento abrir el archivo pdf, todavía abre el original en el navegador, en lugar de descargar la versión renombrada ...
ellockie
ACTUALIZACIÓN: Funciona cuando no hay ningún archivo que se llame directamente (como "Catalogue.pdf" en mi ejemplo). Entonces la redirección funciona perfectamente. ¡Gracias!
ellockie
8

Puedes usar

Response.AddHeader("Content-disposition", "attachment; filename=" + Name);

Mira este ejemplo:

http://www.codeproject.com/KB/aspnet/textfile.aspx

Esto se aplica a ASP.NET. Estoy seguro de que puede encontrar soluciones similares en todos los demás idiomas del lado del servidor. Sin embargo, a mi leal saber y entender, no existe una solución de JavaScript.

mihsathe
fuente
esta es la respuesta (así como la relacionada para PHP). el punto es que el encabezado de respuesta http debe editarse.
user158017
5

Sin el atributo html5, uno puede lograr esto usando php:

Cree un archivo php llamado download.php con este código:

<?php
ob_start();
$file = "yourPDF.pdf"

if (file_exists($file)) 
{
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename='.basename($file));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    ob_clean();
    flush();
    readfile($file);
    exit();
}

Ahora, si desea comenzar a descargar pdf automáticamente, escriba este javascript:

<script>window.location = "download.php";</script>

Si quieres que esto funcione en un enlace, usa esto ...

<a href='javascript:window.location = "download.php"'>
    Download it!
</a>
hlozancic
fuente
4
Solo un aviso de que debe tener cuidado cuando vaya a hacer esto con parámetros de URL. Por ejemplo $file = $_GET['$file'];. Porque entonces también se podría llamar download.php?file=../../../wp-config.phpo cualquier otro recurso dado. ¡La verificación adicional de extensiones, tipos mime y rutas permitidas para descargar (y eliminar cosas como "../") es muy importante!
Giel Berkers
Soy yo o haciendo <a href='javascript...'> es exactamente lo mismo que poner directamente el enlace<a href='download.php'> ?
allan.simon
5

Cuando desee descargar directamente cualquier imagen o archivo pdf desde el navegador en lugar de abrirlo en una nueva pestaña, en javascript debe establecer el valor para descargar el atributo de crear un enlace dinámico

    var path= "your file path will be here"; 
    var save = document.createElement('a');  
    save.href = filePath; 
    save.download = "Your file name here"; 
    save.target = '_blank'; 
    var event = document.createEvent('Event');
    event.initEvent('click', true, true); 
    save.dispatchEvent(event);
   (window.URL || window.webkitURL).revokeObjectURL(save.href);

Para la nueva actualización de Chrome, algún evento temporal no funciona. para ese siguiente código se utilizará

  var path= "your file path will be here"; 
    var save = document.createElement('a');  
    save.href = filePath; 
    save.download = "Your file name here"; 
    save.target = '_blank'; 
    document.body.appendChild(save);
    save.click();
    document.body.removeChild(save);

Agregar un hijo y eliminar un hijo es útil solo para Firefox, el navegador Internet Explorer. En Chrome, funcionará sin agregar ni quitar niño.

Prasad Joshi
fuente
2

La solución que mejor me funcionó fue la que escribió Nick en su blog.

La idea básica de su solución es usar el mod de encabezado de los servidores Apache y editar el .htaccess para incluir una directiva FileMatch que obliga a todos los archivos * .pdf a actuar como una secuencia en lugar de un archivo adjunto. Si bien esto en realidad no implica editar HTML (según la pregunta original), no requiere ninguna programación per se.

La primera razón por la que preferí el enfoque de Nick es porque me permitió configurarlo por carpeta para que los PDF en una carpeta aún se pudieran abrir en el navegador y permitir otros (los que nos gustaría que los usuarios editen y luego vuelvan a cargar) para ser forzado como descargas.

También me gustaría agregar que hay una opción con PDF para publicar / enviar formularios rellenables a través de una API a sus servidores, pero eso lleva un tiempo implementarlo.

La segunda razón fue porque el tiempo es una consideración. Escribir un controlador de archivos PHP para forzar la disposición del contenido en el encabezado () también llevará menos tiempo que una API, pero aún más que el enfoque de Nick.

Si sabe cómo activar un mod de Apache y editar el .htaccss, puede obtenerlo en unos 10 minutos. Requiere hosting Linux (no Windows). Este puede no ser un enfoque apropiado para todos los usos, ya que requiere acceso a un servidor de alto nivel para configurarlo. Como tal, si ha dicho acceso probablemente sea porque ya sabe cómo hacer esas dos cosas. Si no es así, consulte el blog de Nick para obtener más instrucciones.

Strixy
fuente
2

Como la forma html5 (mi respuesta anterior) no está disponible en todos los navegadores, aquí hay otra forma ligeramente pirateada.

Esta solución requiere que esté sirviendo el archivo deseado desde el mismo dominio, O tenga permiso CORS.

  1. Primero descargue el contenido del archivo a través de XMLHttpRequest (Ajax).
  2. Luego, cree un URI de datos codificando en base64 el contenido del archivo y establezca el tipo de medio en application/octet-stream. El resultado debe verse como

data:application/octet-stream;base64,SGVsbG8sIFdvcmxkIQ%3D%3D

Ahora listo location.href = data. Esto hará que el navegador descargue el archivo. Desafortunadamente, no puede establecer el nombre o la extensión del archivo de esta manera. Jugar con el tipo de medios podría dar algo.

Ver detalles: https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs

Sarim
fuente
1

Si está usando HTML5 (y supongo que ahora todos lo usan), hay un atributo llamado download.

ex. <a href="somepathto.pdf" download="filename">

aquí filenamees opcional, pero si se proporciona, tomará este nombre para el archivo descargado.

Akshay
fuente
Lamentablemente, debo admitir que soy demasiado estúpido para entender esta etiqueta. Pongo esto: <a href="download/Curriculum_it.pdf.zip">Download curriculum</a>o aquello: <a href="download/Curriculum_it.pdf.zip" download="Curriculum_it">Download curriculum</a>y no veo absolutamente ninguna diferencia en cómo funciona. Ambos descargando mi .zip. Y en el segundo, el uso de la opción de nombre de archivo parece no hacer nada en absoluto.
Garavani
0

El comportamiento debe depender de cómo esté configurado el navegador para manejar varios tipos de MIME. En este caso, el tipo MIME es application / pdf. Si desea forzar al navegador a descargar el archivo, puede intentar forzar un tipo MIME diferente en los archivos PDF. No recomiendo esto, ya que debería ser la elección de los usuarios lo que sucederá cuando abran un archivo PDF.

Aleksi Yrttiaho
fuente
0

Puede utilizar download.js ( https://github.com/rndme/download y http://danml.com/download.html ). Si el archivo está en una URL externa, debe realizar una solicitud Ajax, pero si no lo está, puede usar la función:

download(Path, name, mime)

Lea su documentación para obtener más detalles en GitHub.

Vishnu S.
fuente
Esta es la mejor solución de JavaScript para descargas en otro dominio.
Edhowler
-1

Finalmente encontré ... crear una etiqueta de ancla dinámica y hacer clic en ella

<script> 
   $('#myclick').click(function(){
       $('body').append('<a id="link" href="mypdf.pdf" 
        download="Payment.pdf">&nbsp;</a>');
       $('#link')[0].click();
   });
</script>

'Payment.pdf' es solo para el nombre personalizado.

Pushpender Singh
fuente
No es necesario generar el enlace de forma dinámica.
Quentin
Tenga en cuenta que el atributo de descarga solo se admite para solicitudes del mismo origen.
Quentin
Esta parece ser la misma respuesta que esta de tres años antes.
Quentin