Tengo una aplicación de JavaScript que envía solicitudes POST de ajax a una determinada URL. La respuesta puede ser una cadena JSON o un archivo (como un archivo adjunto). Puedo detectar fácilmente Content-Type y Content-Disposition en mi llamada ajax, pero una vez que detecto que la respuesta contiene un archivo, ¿cómo ofrezco al cliente que lo descargue? He leído varios hilos similares aquí, pero ninguno de ellos proporciona la respuesta que estoy buscando.
Por favor, por favor, no publique respuestas que sugieran que no debería usar ajax para esto o que debería redirigir el navegador, porque nada de esto es una opción. Usar un formulario HTML simple tampoco es una opción. Lo que sí necesito es mostrar un diálogo de descarga al cliente. ¿Se puede hacer esto y cómo?
fuente
Respuestas:
Cree un formulario, use el método POST, envíe el formulario; no hay necesidad de un iframe. Cuando la página del servidor responde a la solicitud, escriba un encabezado de respuesta para el tipo mime del archivo, y presentará un cuadro de diálogo de descarga. Lo he hecho varias veces.
Desea el tipo de contenido de la aplicación / descarga: solo busque cómo proporcionar una descarga para el idioma que esté utilizando.
fuente
No te rindas tan rápido, porque esto se puede hacer (en navegadores modernos) utilizando partes de FileAPI:
Aquí está la versión anterior usando jQuery.ajax. Puede destrozar datos binarios cuando la respuesta se convierte en una cadena de algún conjunto de caracteres.
fuente
document.body.removeChild(a);
var blob =this.responce; /** if (typeof File === 'function') { try { blob = new File([this.response], filename, { type: type }); } catch (e) { /* Edge */ } } if (typeof blob === 'undefined') { blob = new Blob([this.response], { type: type }); } */
window.location.href = downloadUrl
lugar dewindow.location = downloadUrl
Enfrenté el mismo problema y lo resolví con éxito. Mi caso de uso es este.
" Publique datos JSON en el servidor y reciba un archivo de Excel. Ese archivo de Excel es creado por el servidor y devuelto como respuesta al cliente. Descargue esa respuesta como un archivo con nombre personalizado en el navegador "
El fragmento anterior solo hace lo siguiente
Aquí necesitamos establecer cuidadosamente algunas cosas en el lado del servidor. Configuré algunos encabezados en Python Django HttpResponse. Debe configurarlos en consecuencia si usa otros lenguajes de programación.
Desde que descargo xls (excel) aquí, ajusté contentType al anterior. Debe configurarlo de acuerdo con su tipo de archivo. Puede usar esta técnica para descargar cualquier tipo de archivo.
fuente
¿Qué idioma del lado del servidor estás usando? En mi aplicación, puedo descargar fácilmente un archivo de una llamada AJAX configurando los encabezados correctos en la respuesta de PHP:
Establecer encabezados del lado del servidor
De hecho, esto 'redirigirá' el navegador a esta página de descarga, pero como dijo @ahren alread en su comentario, no se alejará de la página actual.
Se trata de configurar los encabezados correctos, así que estoy seguro de que encontrará una solución adecuada para el lenguaje del lado del servidor que está utilizando si no es PHP.
Manejo del lado del cliente de respuesta
Suponiendo que ya sabe cómo hacer una llamada AJAX, en el lado del cliente ejecuta una solicitud AJAX al servidor. Luego, el servidor genera un enlace desde donde se puede descargar este archivo, por ejemplo, la URL 'hacia adelante' a la que desea apuntar. Por ejemplo, el servidor responde con:
Cuando procesas la respuesta, inyectas una
iframe
en tu cuerpo y configuras eliframe
SRC de la URL que acabas de recibir (usando jQuery para facilitar este ejemplo):Si ha configurado los encabezados correctos como se muestra arriba, el iframe forzará un cuadro de diálogo de descarga sin desplazar el navegador fuera de la página actual.
Nota
Adición adicional en relación a su pregunta; Creo que es mejor devolver siempre JSON al solicitar cosas con tecnología AJAX. Después de recibir la respuesta JSON, puede decidir qué hacer con el lado del cliente. Tal vez, por ejemplo, más adelante desee que el usuario haga clic en un enlace de descarga a la URL en lugar de forzar la descarga directamente, en su configuración actual tendría que actualizar tanto el cliente como el servidor para hacerlo.
fuente
Para aquellos que buscan una solución desde una perspectiva angular, esto funcionó para mí:
fuente
link.download = ""
resultados en un nombre de archivo guid aleatorio ylink.download = null
resultados en un archivo llamado "nulo".INPUT
del elementoHTMLInputElement.files
. Consulte los documentos de MDN en la entrada del archivo para obtener más detalles.Así es como conseguí que esto funcionara https://stackoverflow.com/a/27563953/2845977
Respuesta actualizada usando download.js
fuente
success: function (response, status, request) { download(response, "filename.txt", "application/text"); }
Veo que ya ha encontrado una solución, sin embargo, solo quería agregar información que pueda ayudar a alguien que intenta lograr lo mismo con grandes solicitudes POST.
Tuve el mismo problema hace un par de semanas, de hecho, no es posible lograr una descarga "limpia" a través de AJAX, el Grupo Filament creó un complemento jQuery que funciona exactamente como ya lo descubrió, se llama jQuery File Descargar sin embargo, hay una desventaja en esta técnica.
Si envía solicitudes grandes a través de AJAX (digamos archivos + 1 MB), tendrá un impacto negativo en la capacidad de respuesta. En conexiones lentas a Internet, tendrá que esperar mucho hasta que se envíe la solicitud y también esperar a que se descargue el archivo. No es como un "clic" instantáneo => "emergente" => "inicio de descarga". Es más como "hacer clic" => "esperar hasta que se envíen los datos" => "esperar respuesta" => "inicio de descarga", lo que hace que parezca que el archivo duplica su tamaño porque tendrá que esperar a que se envíe la solicitud a través de AJAX y recuperarlo como un archivo descargable.
Si está trabajando con archivos de tamaño pequeño <1 MB, no lo notará. Pero como descubrí en mi propia aplicación, para archivos de mayor tamaño es casi insoportable.
Mi aplicación permite a los usuarios exportar imágenes generadas dinámicamente, estas imágenes se envían a través de solicitudes POST en formato base64 al servidor (es la única forma posible), luego se procesan y se envían a los usuarios en forma de archivos .png, .jpg, base64 Las cadenas de imágenes + 1 MB son enormes, esto obliga a los usuarios a esperar más de lo necesario para que el archivo comience a descargarse. En conexiones lentas a Internet puede ser realmente molesto.
Mi solución para esto fue escribir temporalmente el archivo en el servidor, una vez que esté listo, generar dinámicamente un enlace al archivo en forma de un botón que cambia entre los estados "Por favor, espere ..." y "Descargar" y al mismo tiempo vez, imprima la imagen base64 en una ventana emergente de vista previa para que los usuarios puedan hacer clic con el botón derecho y guardarla. Esto hace que todo el tiempo de espera sea más soportable para los usuarios, y también acelera las cosas.
Actualización 30 de septiembre 2014:
Descargar Script Ejemplo:
Sé que esto va mucho más allá de lo que pidió el OP, sin embargo, sentí que sería bueno actualizar mi respuesta con mis hallazgos. Cuando estaba buscando soluciones a mi problema, leí muchos hilos de "Descarga de datos POST AJAX" que no me dieron la respuesta que estaba buscando, espero que esta información ayude a alguien que busca lograr algo como esto.
fuente
jQuery File Download
único me redirige a la url. Lo llamo así:jQuery.download("api/ide/download-this-file.php", {filePath: path2Down}, "POST");
.Quiero señalar algunas dificultades que surgen al usar la técnica en la respuesta aceptada, es decir, usar una publicación de formulario:
No puede establecer encabezados en la solicitud. Si su esquema de autenticación involucra encabezados, un Json-Web-Token pasado en el encabezado de Autorización, tendrá que encontrar otra forma de enviarlo, por ejemplo, como un parámetro de consulta.
Realmente no se puede saber cuándo ha finalizado la solicitud. Bueno, puede usar una cookie que se establece en la respuesta, como lo hizo jquery.fileDownload , pero está LEJOS de ser perfecta. No funcionará para solicitudes concurrentes y se romperá si nunca llega una respuesta.
Si el servidor responde con un error, el usuario será redirigido a la página de error.
Solo puede usar los tipos de contenido admitidos por un formulario . Lo que significa que no puedes usar JSON.
Terminé usando el método de guardar el archivo en S3 y enviando una URL previamente firmada para obtener el archivo.
fuente
Para aquellos que buscan un enfoque más moderno, pueden usar el
fetch API
. El siguiente ejemplo muestra cómo descargar un archivo de hoja de cálculo. Se hace fácilmente con el siguiente código.Creo que este enfoque es mucho más fácil de entender que otras
XMLHttpRequest
soluciones. Además, tiene una sintaxis similar aljQuery
enfoque, sin la necesidad de agregar bibliotecas adicionales.Por supuesto, recomendaría verificar en qué navegador está desarrollando, ya que este nuevo enfoque no funcionará en IE. Puede encontrar la lista completa de compatibilidad del navegador en el siguiente [enlace] [1].
Importante : en este ejemplo, estoy enviando una solicitud JSON a un servidor que escucha en el dado
url
. Estourl
debe establecerse, en mi ejemplo, supongo que conoce esta parte. Además, considere los encabezados necesarios para que su solicitud funcione. Como estoy enviando un JSON, debo agregar elContent-Type
encabezado y configurarloapplication/json; charset=utf-8
para que el servidor sepa el tipo de solicitud que recibirá.fuente
Aquí está mi solución usando un formulario oculto temporal.
Tenga en cuenta que uso masivamente JQuery, pero puede hacer lo mismo con JS nativo.
fuente
Como han dicho otros, puede crear y enviar un formulario para descargar a través de una solicitud POST. Sin embargo, no tiene que hacer esto manualmente.
Una biblioteca realmente simple para hacer exactamente esto es jquery.redirect . Proporciona una API similar al
jQuery.post
método estándar :fuente
Esta es una pregunta de 3 años, pero tuve el mismo problema hoy. Busqué su solución editada, pero creo que puede sacrificar el rendimiento porque tiene que hacer una doble solicitud. Entonces, si alguien necesita otra solución que no implique llamar al servicio dos veces, esta es la forma en que lo hice:
Este formulario solo se usa para llamar al servicio y evitar el uso de window.location (). Después de eso, simplemente tiene que enviar un formulario desde jquery para llamar al servicio y obtener el archivo. Es bastante simple, pero de esta manera puedes hacer una descarga usando un POST . Ahora sé que esto podría ser más fácil si el servicio al que llama es un GET , pero ese no es mi caso.
fuente
Usé este FileSaver.js . En mi caso con archivos csv, hice esto (en coffescript):
Creo que para el caso más complicado, los datos deben procesarse correctamente. Bajo el capó, FileSaver.js implementa el mismo enfoque de la respuesta de Jonathan Enmienda .
fuente
ver: http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/ devolverá un blob como respuesta, que luego se puede poner en el protector de archivos
fuente
Para obtener la respuesta de Jonathan Amends para trabajar en Edge, hice los siguientes cambios:
a esto
Preferiría haber publicado esto como un comentario, pero no tengo suficiente reputación para eso
fuente
Aquí está mi solución, recopilada de diferentes fuentes: Implementación del lado del servidor:
Implementación del lado del cliente (usando jquery):
fuente
Hay otra solución para descargar una página web en ajax. Pero me estoy refiriendo a una página que primero debe procesarse y luego descargarse.
Primero debe separar el procesamiento de la página de la descarga de resultados.
1) Solo los cálculos de la página se realizan en la llamada ajax.
Espero que esta solución pueda ser útil para muchos, como lo fue para mí.
fuente
Si la respuesta es un Array Buffer , intente esto bajo un evento de éxito en Ajax:
fuente
A continuación se muestra mi solución para descargar varios archivos dependiendo de una lista que consiste en algunos identificadores y buscar en la base de datos, los archivos estarán determinados y listos para descargar, si es que existen. Estoy llamando a la acción C # MVC para cada archivo usando Ajax.
Y sí, como dijeron otros, es posible hacerlo en jQuery Ajax. Lo hice con éxito Ajax y siempre estoy enviando la respuesta 200.
Entonces, esta es la clave:
Y este es mi código:
Entonces llamando:
C # MVC:
Siempre que devuelva la respuesta 200, el éxito en Ajax puede funcionar con ella, puede verificar si el archivo realmente existe o no, ya que la línea a continuación en este caso sería falsa y puede informar al usuario sobre eso:
fuente
Necesitaba una solución similar a la de @ alain-cruz, pero en nuxt / vue con múltiples descargas. Sé que los navegadores bloquean la descarga de múltiples archivos, y también tengo una API que devuelve un conjunto de datos con formato csv. Al principio iba a usar JSZip, pero necesitaba el soporte de IE, así que aquí está mi solución. Si alguien puede ayudarme a mejorar esto, sería genial, pero hasta ahora me está funcionando.
API devuelve:
page.vue:
fuente