descargar archivo usando una solicitud ajax


Quiero enviar una "solicitud de descarga ajax" cuando hago clic en un botón, así que lo intenté de esta manera:

Javascript:

var xhr = new XMLHttpRequest();
xhr.open("GET", "download.php");
xhr.send();

Descargar.php:

<?
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename= file.txt");
header("Content-Transfer-Encoding: binary");    
readfile("file.txt");
?>

Pero no funciona como se esperaba, ¿cómo puedo hacerlo ? Gracias de antemano

Author: Manuel Di Iorio, 2013-12-30

7 answers

Actualización de Abril 27, 2015

En la escena de HTML5 aparece el atributo de descarga . Es soportado en Firefox y Chrome, y pronto llegará a IE11. Dependiendo de sus necesidades, puede usarlo en lugar de una solicitud AJAX (o usar window.location) siempre y cuando el archivo que desea descargar esté en el mismo origen que su sitio.

Siempre puede hacer que la solicitud AJAX / window.location sea una alternativa usando algo de JavaScript para probar si download es compatible y si no, cambiarlo a llamar window.location.

Respuesta original

No puede hacer que una solicitud AJAX abra la solicitud de descarga ya que físicamente tiene que navegar hasta el archivo para solicitar la descarga. En su lugar, puede usar una función de éxito para navegar hasta descargar.php. Esto abrirá la solicitud de descarga, pero no cambiará la página actual.

$.ajax({
    url: 'download.php',
    type: 'POST',
    success: function() {
        window.location = 'download.php';
    }
});

Aunque esto responde a la pregunta, es mejor simplemente usar window.location y evitar la solicitud AJAX por completo.

 88
Author: Steven Lambert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:25

En realidad no necesitas ajax para esto. Si acaba de configurar " descargar.php " como el href en el botón, o, si no es un enlace use:

window.location = 'download.php';

El navegador debe reconocer la descarga binaria y no cargar la página real, sino simplemente servir el archivo como una descarga.

 38
Author: Jelle Kralt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-23 07:25:54

Para hacer que el navegador descargue un archivo, necesita hacer la solicitud de esta manera:

 function downloadFile(urlToSend) {
     var req = new XMLHttpRequest();
     req.open("GET", urlToSend, true);
     req.responseType = "blob";
     req.onload = function (event) {
         var blob = req.response;
         var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
         var link=document.createElement('a');
         link.href=window.URL.createObjectURL(blob);
         link.download=fileName;
         link.click();
     };

     req.send();
 }
 15
Author: João Marcos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-15 16:49:46

Es posible. Puede hacer que la descarga se inicie desde dentro de una función ajax, por ejemplo, justo después de la .se crea el archivo CSV.

Tengo una función ajax que exporta una base de datos de contactos a a .archivo csv, y justo después de que termine, se inicia automáticamente el .descarga de archivos CSV. Entonces, después de obtener el responseText y todo está bien, redirijo el navegador de esta manera:

window.location="download.php?filename=export.csv";

Mi descarga.el archivo php se ve así:

<?php

    $file = $_GET['filename'];

    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header("Content-Disposition: attachment; filename=".$file."");
    header("Content-Transfer-Encoding: binary");
    header("Content-Type: binary/octet-stream");
    readfile($file);

?>

No hay actualización de página lo que sea y el archivo automáticamente comienza a descargarse.

NOTA - Probado en los siguientes navegadores:

Chrome v37.0.2062.120 
Firefox v32.0.1
Opera v12.17
Internet Explorer v11
 13
Author: Pedro Sousa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-16 11:00:57

Solución de navegador cruzado, probado en Chrome, Firefox, Edge, IE11.

En el DOM, agregue una etiqueta de enlace oculta:

<a id="target" style="display: none"></a>

Entonces:

var req = new XMLHttpRequest();
req.open("GET", downloadUrl, true);
req.responseType = "blob";

req.onload = function (event) {
  var blob = req.response;
  var fileName = null;
  var contentType = req.getResponseHeader("content-type");

  // IE/EDGE seems not returning some response header
  if (req.getResponseHeader("content-disposition")) {
    var contentDisposition = req.getResponseHeader("content-disposition");
    fileName = contentDisposition.substring(contentDisposition.indexOf("=")+1);
  } else {
    fileName = "unnamed." + contentType.substring(contentType.indexOf("/")+1);
  }

  if (window.navigator.msSaveOrOpenBlob) {
    // Internet Explorer
    window.navigator.msSaveOrOpenBlob(new Blob([blob], {type: contentType}), fileName);
  } else {
    var el = document.getElementById("target");
    el.href = window.URL.createObjectURL(blob);
    el.download = fileName;
    el.click();
  }
};
req.send();
 5
Author: leo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-05 14:05:08
 1
Author: Telmo Dias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-13 10:11:39

Decodificar un nombre de archivo desde el encabezado es un poco más complejo...

    var filename = "default.pdf";
    var disposition = req.getResponseHeader('Content-Disposition');

    if (disposition && disposition.indexOf('attachment') !== -1) 
    {
       var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
       var matches = filenameRegex.exec(disposition);

       if (matches != null && matches[1]) 
           filename = matches[1].replace(/['"]/g, '');
    }
 0
Author: Lumic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-19 00:01:10