Forzar para abrir la ventana emergente "Guardar como ..." abierta en el enlace de texto haga clic para PDF en HTML

173

Tengo algunos catálogos PDF de gran tamaño en mi sitio web, y necesito vincularlos como descarga. Cuando busqué en Google, encontré tal cosa anotada a continuación. Debería abrir la ventana emergente " Guardar como ... " al hacer clic en el enlace ...

 <head>
    <meta name="content-disposition" content="inline; filename=filename.pdf">
    ...

Pero no funciona: / Cuando enlace a un archivo como se muestra a continuación, solo se vincula al archivo y está tratando de abrir el archivo.

    <a href="filename.pdf" title="Filie Name">File name</a>

ACTUALIZACIÓN (según las respuestas a continuación):

Como veo, no hay una solución de navegador cruzado 100% confiable para esto. Probablemente la mejor manera es usar uno de los servicios web que se enumeran a continuación, y dar un enlace de descarga ...

diseñador-prueba-codificación
fuente
1
no sirva el mimetype para archivos pdf.
bhups
Probé su solución actualizada, artmania, pero ocurrió el mismo problema que tuve en Safari. Obtengo lo que parece el PDF en la ventana del navegador, y solo cuando hago clic en las pestañas "vista previa" o "descargar" en la parte inferior obtengo la función de búsqueda que necesito desesperadamente.
heathwaller
sin el clic: stackoverflow.com/questions/2598658/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
similar pero menos específico del tipo de archivo: stackoverflow.com/questions/1465573/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

268

De una respuesta a Forzar un navegador para guardar el archivo como después de hacer clic en el enlace :

<a href="path/to/file" download>Click here to download</a>
Ayush Gupta
fuente
17
En el momento de este comentario, el downloadatributo está limitado a Chrome, Firefox y Opera. Incluso las versiones recientes de IE y Safari no lo admiten. Para soporte futuro: consulte caniuse.com/#feat=download !
Sygmoral
La comprobación de errores de Netbeans se queja, pero parece funcionar bien. Puede especificar un nombre preliminar para el nuevo archivo de esta manera: download = "myFile.txt"
Yster
1
Esto funciona en Edge al momento de escribir este comentario, y parece ser la única forma posible de detener la apertura de archivos PDF con hipervínculos en el intento muy pobre de Edge en un visor de PDF.
En el momento de este comentario, lo he probado en Chrome, Opera, Edge, Mozilla. Todo lo último. Está trabajando en todos excepto en Mozilla.
SI
77
Esto solo funciona para enlaces del mismo origen, como se menciona en caniuse.com/#feat=download . Si sus enlaces son de origen cruzado, su única opción (por ahora) es forzar el tipo de respuesta a "application / octet-stream", como sugieren muchas respuestas. Si no tiene acceso al servidor, puede intentar proxy y configurar el encabezado de respuesta manualmente.
Jean-Baptiste
81
<a href="file link" download target="_blank">Click here to download</a>

A mí me funciona en Firefox y Chrome.

DrWaky
fuente
2
Sin embargo, es exactamente lo mismo que la respuesta principal actual, de Ayush Gupta en 2013. Sin embargo, target="_blank"puede hacer que sea un poco más utilizable para navegadores no compatibles (los PDF se abren en una nueva ventana / pestaña, en lugar de sobrescribir la página actual).
Sygmoral
3
Para mí, target="_blank"fue necesario ya que downloadsolo no se pudo activar la descarga correctamente (Chrome)
casraf
2
Si proporciona una cadena en el downloadatributo, se utilizará como nombre de archivo. Lo estoy usando en los guiones de usuario todo el tiempo.
weaknespase
34

Las metaetiquetas no son una forma confiable de lograr este resultado. En general, ni siquiera debe hacer esto: debe dejarse en manos del usuario / agente de usuario decidir qué hacer con el contenido que proporciona. El usuario siempre puede forzar a su navegador a descargar el archivo si lo desea.

Si aún desea forzar al navegador a descargar el archivo, modifique los encabezados HTTP directamente. Aquí hay un ejemplo de código PHP:

$path = "path/to/file.pdf";
$filename = "file.pdf";
header('Content-Transfer-Encoding: binary');  // For Gecko browsers mainly
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT');
header('Accept-Ranges: bytes');  // Allow support for download resume
header('Content-Length: ' . filesize($path));  // File size
header('Content-Encoding: none');
header('Content-Type: application/pdf');  // Change the mime type if the file is not PDF
header('Content-Disposition: attachment; filename=' . $filename);  // Make the browser display the Save As dialog
readfile($path);  // This is necessary in order to get it to actually download the file, otherwise it will be 0Kb

Tenga en cuenta que esto es solo una extensión del protocolo HTTP; algunos navegadores pueden ignorarlo de todos modos.

Karel Petranek
fuente
44
En la práctica, creo que esto se implementa ampliamente.
Matthew Wilson el
Esta es la mejor solución, sin problemas y funciona. Puede descargar directamente cualquier tipo de archivo con este método. +1
casraf
3
Content-Transfer-Encoding no existe en HTTP. Codificación de contenido: ninguno es inútil.
Julian Reschke
HAGA UNA NOTA en su respuesta, que el archivo IF es de un servidor / dominio externo, entonces esta respuesta puede no ser la solución ...
T.Todua
Me gustaría agregar que he tenido este código o un error similar en ciertos servidores cuando los archivos se hacen grandes (> 80 MB en mi caso). Usar ob_end_flush()tampoco ayudó.
Hendrik
22

Tuve este mismo problema y encontré una solución que ha funcionado muy bien hasta ahora. Pones el siguiente código en tu .htaccessarchivo:

<FilesMatch "\.(?i:pdf)$">
  ForceType application/octet-stream
  Header set Content-Disposition attachment
</FilesMatch>

Vino de Forzar un archivo para descargar en lugar de aparecer en el navegador .

Tony
fuente
44
Esto funcionó bien, ya que tenía un directorio de documentos en particular para descargas. Omití ForceType, solo para dejar que los tipos permanezcan como están. Tampoco necesitaba la mayúscula y minúscula; el mío ya no distingue entre mayúsculas y minúsculas. Agregué un par de tipos adicionales, incluido opcional-x para las extensiones de Office antiguas / nuevas:<FilesMatch "\.(pdf|xlsx?|docx?)$">
goodeye
Esto funcionó maravillosamente, incluso en OSX Safari, donde otras respuestas (incluida la aceptada, como señaló un comentarista allí) se limitan a ciertos navegadores que admiten la función HTML dada. Este me parece más ideal ya que funcionó en todos los ámbitos, aunque requiere un acceso de mayor nivel a los archivos de configuración del servidor.
bwright
También podría poner eso en su archivo apache.conf, no uso .htaccess ya que requiere más recursos.
Michael Fever
¿Cómo implementaría esto un sitio web alojado en Windows, ya que no pueden leer archivos htaccess?
PoloHoleSet
10

Encontré una solución muy simple para Firefox (solo funciona con un href relativo en lugar de un href directo): agregar type="application/octet-stream":

<a href="./file.pdf" id='example' type="application/octet-stream">Example</a>
Usuario
fuente
1
@ Martin Chrome en Chrome OS y Firefox en Linux. Resulta que el archivo debe ser local para que funcione. Mi href era una url para el almacenamiento en la nube.
ttfreeman
7

Intente agregar esta línea a su archivo .htaccess.

AddType application/octet-stream .pdf

Espero que funcione, ya que es independiente del navegador.

Sharad Gautam
fuente
Me interesaría saber por qué se ha votado negativamente
Nathan Hornby
Las personas intentan modificar la funcionalidad principal de un servidor en sitios de alojamiento gratuitos y luego votan en contra porque no pueden hacer que funcione. Cualquier otra solución tendrá advertencias porque es un "truco" para reemplazar esto.
Carrito abandonado el
Lo rechazo porque es la solución incorrecta al problema. Es una mala idea meterse con tipos de recursos.
Brad
@NathanHornby: no lo rechacé, pero esto no funcionaría para ningún sitio alojado en Windows, ya que no usan .htaccess.
PoloHoleSet
No voté en contra, pero esta solución afecta ciegamente TODOS los archivos de ese sufijo. Es indiscriminado y, por lo tanto, no será apropiado en todos los casos.
JBH
6

Por lo general, sucede porque la configuración o los complementos de algunos navegadores abren directamente el PDF en la misma ventana como una página web simple.

Lo siguiente podría ayudarlo. Lo hice en PHP hace unos años. Pero actualmente no estoy trabajando en esa plataforma.

<?php
    if (isset($_GET['file'])) {
        $file = $_GET['file'];
        if (file_exists($file) && is_readable($file) && preg_match('/\.pdf$/',$file)) {
            header('Content-type: application/pdf');
            header("Content-Disposition: attachment; filename=\"$file\"");
            readfile($file);
        }
    }
    else {
        header("HTTP/1.0 404 Not Found");
        echo "<h1>Error 404: File Not Found: <br /><em>$file</em></h1>";
    }
?>

Guarde lo anterior como download.php .

Guarde este pequeño fragmento como un archivo PHP en algún lugar de su servidor y puede usarlo para realizar una descarga de archivos en el navegador, en lugar de mostrarlo directamente. Si desea servir archivos que no sean PDF, elimine o edite la línea 5.

Puedes usarlo así:

Agregue el siguiente enlace a su archivo HTML.

<a href="download.php?file=my_pdf_file.pdf">Download the cool PDF.</a>

Referencia de: este blog

Ashay
fuente
77
Esta parece ser una buena manera de servir cada archivo en su servidor a cualquiera que esté prestando atención. download.php?file=database_password_file.phppor ejemplo.
pbarney
5

Simplemente ponga el siguiente código en su .htaccessarchivo:

AddType application/octet-stream .csv
AddType application/octet-stream .xls
AddType application/octet-stream .doc
AddType application/octet-stream .avi
AddType application/octet-stream .mpg
AddType application/octet-stream .mov
AddType application/octet-stream .pdf

O también puedes hacer trucos con JavaScript

element.setAttribute( 'download', whatever_string_you_want);
manish1706
fuente
1
¿No supone esto que el servidor web es Apache ?
Peter Mortensen
5

Acabo de usar esto, pero no sé si funciona en todos los navegadores.

Funciona en Firefox:

<a href="myfile.pdf" download>Click to Download</a>
NowLiveLove
fuente
1
Eso se sugiere, y con más información de fondo, en una respuesta anterior .
usr2564301
4

Una manera realmente simple de lograr esto, sin usar sitios de descarga externos o modificar encabezados, etc., es simplemente crear un archivo ZIP con el PDF dentro y vincularlo directamente al archivo ZIP. Esto SIEMPRE activará el cuadro de diálogo Guardar / Abrir, y aún es fácil para las personas hacer doble clic en las ventanas PDF que se inicia el programa asociado con .zip.

Por cierto, también estaba buscando una respuesta, ya que la mayoría de los complementos PDF integrados en el navegador tardan demasiado en mostrar cualquier cosa (y a menudo bloquean el navegador mientras se carga el PDF).

Señor selva
fuente
31
Terrible usabilidad. Muchos usuarios finales no sabrían qué hacer con un archivo zip.
CodeWarrior
1
¡A veces los solutioans simples son las mejores soluciones!
elrado
1
No es una buena solución. Tengo exactamente ese problema con Firefox y un archivo ZIP. ¿Qué tengo que hacer? ZIP el archivo? En ese caso, modificar los encabezados HTTP podría ser una solución, pero no tengo acceso a eso.
Arnaud Weil
2

Una solución del lado del servidor es más compatible, hasta que el atributo "descargar" se implemente en todos los navegadores.

Un ejemplo de Python podría ser un controlador de solicitud HTTP personalizado para un almacén de archivos. Los enlaces que apuntan al almacén de archivos se generan así:

http://www.myfilestore.com/filestore/13/130787e71/download_as/desiredName.pdf

Aquí está el código:

class HTTPFilestoreHandler(SimpleHTTPRequestHandler):

    def __init__(self, fs_path, *args):
        self.fs_path = fs_path                          # Filestore path
        SimpleHTTPRequestHandler.__init__(self, *args)

    def send_head(self):
        # Overwrite SimpleHTTPRequestHandler.send_head to force download name
        path = self.path
        get_index = (path == '/')
        self.log_message("path: %s" % path)
        if '/download_as/' in path:
            p_parts = path.split('/download_as/')
            assert len(p_parts) == 2, 'Bad download link:' + path
            path, download_as = p_parts
        path = self.translate_path(path )
        f = None
        if os.path.isdir(path):
            if not self.path.endswith('/'):
                # Redirect browser - doing basically what Apache does
                self.send_response(301)
                self.send_header("Location", self.path + "/")
                self.end_headers()
                return None
            else:
                return self.list_directory(path)
        ctype = self.guess_type(path)
        try:
            f = open(path, 'rb')
        except IOError:
            self.send_error(404, "File not found")
            return None
        self.send_response(200)
        self.send_header("Content-type", ctype)
        fs = os.fstat(f.fileno())
        self.send_header("Expires", '0')
        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
        self.send_header("Cache-Control", 'must-revalidate, post-check=0, pre-check=0')
        self.send_header("Content-Transfer-Encoding", 'binary')
        if download_as:
            self.send_header("Content-Disposition", 'attachment; filename="%s"' % download_as)
        self.send_header("Content-Length", str(fs[6]))
        self.send_header("Connection", 'close')
        self.end_headers()
        return f


class HTTPFilestoreServer:

    def __init__(self, fs_path, server_address):
        def handler(*args):
            newHandler = HTTPFilestoreHandler(fs_path, *args)
            newHandler.protocol_version = "HTTP/1.0"
        self.server = BaseHTTPServer.HTTPServer(server_address, handler)

    def serve_forever(self, *args):
        self.server.serve_forever(*args)


def start_server(fs_path, ip_address, port):
    server_address = (ip_address, port)
    httpd = HTTPFilestoreServer(fs_path, server_address)

    sa = httpd.server.socket.getsockname()
    print "Serving HTTP on", sa[0], "port", sa[1], "..."
    httpd.serve_forever()
platillo
fuente
2

Una manera muy fácil de hacer esto, si necesita forzar la descarga de un solo enlace en su página, es usar el atributo de descarga HTML5 en el enlace href.

Ver: http://davidwalsh.name/download-attribute

con esto puede cambiar el nombre del archivo que descargará el usuario y al mismo tiempo fuerza la descarga.

Se ha debatido si es una buena práctica o no, pero en mi caso tengo un visor incrustado para un archivo PDF y el visor no ofrece un enlace de descarga, por lo que tengo que proporcionar uno por separado. Aquí quiero asegurarme de que el usuario no abra el PDF en el navegador web, lo cual sería confuso.

Esto no necesariamente abrirá el cuadro de diálogo Guardar como, pero descargará el enlace directamente al destino de descarga preestablecido. Y, por supuesto, si está haciendo un sitio para otra persona, y necesita que escriban manualmente los atributos en sus enlaces, probablemente sea una mala idea, pero si hay una forma de obtener el atributo en los enlaces, esta puede ser una solución ligera.

JJxyz
fuente
1

Esta es una publicación anterior, pero aquí está la solución que tengo en JavaScript para usar la biblioteca jQuery.

<script>
(function($){
    var download = [];
    $('a.force-download, .force-download a').each(function(){
        // Collect info
        var $this = $(this),
            $href = $this.attr('href'),
            $split = $href.split('/'),
            $name = document.title.replace(/[\W_]/gi, '-').replace(/-{2,}/g, '-'); // get title and clean it for the URL

        // Get filename from URL
        if($split[($split.length-1)])
        {
            $tmp = $split[($split.length-1)];
            $tmp = $tmp.split('.');
            $name = $tmp[0].replace(/[\W_]/gi, '-').replace(/-{2,}/g, '-');
        }

        // If name already exists, put timestamp there
        if($.inArray($name, download) > -1)
        {
            $name = $name + '-' + Date.now().replace(/[\W]/gi, '-');
        }

        $(this).attr("download", $name);
        download.push($name);
    });
}(jQuery || window.jQuery))
</script>

Solo necesita usar la clase force-downloaddentro de su <a>etiqueta y forzará la descarga automáticamente. También puede agregarlo a padre divy recogerá todos los enlaces dentro de él.

Ejemplo:

<a href="/some/good/url/Post-Injection_Post-Surgery_Instructions.pdf" class="force-download" target="_blank">Download PDF</a>

Esto es genial para WordPress y cualquier otro sistema o sitio web personalizado.

Ivijan Stefan Stipić
fuente
0

Después del nombre del archivo en el código HTML agrego ?forcedownload=1

Esta ha sido la forma más sencilla para que active un cuadro de diálogo para guardar o descargar.

Bonnie
fuente
0

Si tiene un complemento dentro del navegador que sabe cómo abrir un archivo PDF, se abrirá directamente. Como en el caso de imágenes y contenido HTML.

Entonces, el enfoque alternativo es no enviar su tipo MIME en la respuesta. De esta manera, el navegador nunca sabrá qué complemento debe abrirlo. Por lo tanto, le dará un cuadro de diálogo Guardar / Abrir .

sushil bharwani
fuente
Eso es difícil de lograr porque es el servidor que envía el tipo MIME y cuando se vincula directamente a un archivo PDF, no puede cambiar los encabezados.
Karel Petranek
0

Simplemente tuve un problema muy similar con el problema agregado que necesitaba para crear enlaces de descarga a archivos dentro de un archivo ZIP.

Primero intenté crear un archivo temporal, luego proporcioné un enlace al archivo temporal, pero descubrí que algunos navegadores solo mostraban el contenido (un archivo CSV Excel) en lugar de ofrecer la descarga. Finalmente encontré la solución usando un servlet. Funciona tanto en Tomcat como en GlassFish, y lo probé en Internet Explorer 10 y Chrome.

El servlet toma como entrada un nombre de ruta completo para el archivo ZIP y el nombre del archivo dentro del archivo zip que debe descargarse.

Dentro de mi archivo JSP tengo una tabla que muestra todos los archivos dentro del zip, con enlaces que dicen: onclick='download?zip=<%=zip%>&csv=<%=csv%>'

El código del servlet está en download.java:

package myServlet;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.zip.*;
import java.util.*;

// Extend HttpServlet class
public class download extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        PrintWriter out = response.getWriter(); // now we can write to the client

        String filename = request.getParameter("csv");
        String zipfile = request.getParameter("zip");

        String aLine = "";

        response.setContentType("application/x-download");
        response.setHeader( "Content-Disposition", "attachment; filename=" + filename); // Force 'save-as'
        ZipFile zip = new ZipFile(zipfile);
        for (Enumeration e = zip.entries(); e.hasMoreElements();) {
            ZipEntry entry = (ZipEntry) e.nextElement();
            if(entry.toString().equals(filename)) {
                InputStream is = zip.getInputStream(entry);
                BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 65536);
                while ((aLine = br.readLine()) != null) {
                    out.println(aLine);
                }
                is.close();
                break;
            }
        }
    }
}

Para compilar en Tomcat necesita que el classpath incluya tomcat \ lib \ servlet-api.jar o en GlassFish: glassfish \ lib \ j2ee.jar

Pero cualquiera de los dos funcionará en ambos. También necesita configurar su servlet web.xml.

mljm
fuente
0

Agregue un encabezado de respuesta Content-Disposition: adjunto; seguido del nombre del archivo. Eliminar la disposición del contenido meta; en línea; que abrirá el documento en la misma ventana

En java se establece como

response.setHeader("Content-Disposition", "attachment;filename=test.jpg");
johnmin
fuente
-2

Con archivos PDF grandes, el navegador se bloquea. En Mozilla, menú HerramientasOpcionesAplicaciones , luego al lado del tipo de contenido documento Adobe Acrobat. En el menú desplegable Acción, seleccione Preguntar siempre .

Esto no funcionó para mí, así que lo que funcionó fue:

Herramientas de menú * → ComplementosAdobe Acrobat (complemento Adobe PDF para Firefox) → DESACTIVAR. ¡Ahora puedo descargar libros electrónicos!

Joojoo
fuente
2
¿leíste la pregunta? esta no es una respuesta cruzada del navegador
Mark
1
@mark también son instrucciones para que un usuario solicite descargas forzadas de archivos PDF, no el propietario de un sitio web.
Nathan Hornby