Tengo una aplicación web de una sola página basada en jquery. Se comunica con un servicio web RESTful a través de llamadas AJAX.
Estoy tratando de lograr lo siguiente:
- Envíe una POST que contenga datos JSON a una URL REST.
- Si la solicitud especifica una respuesta JSON, se devuelve JSON.
- Si la solicitud especifica una respuesta PDF / XLS / etc., se devuelve un binario descargable.
Tengo 1 y 2 trabajando ahora, y la aplicación jquery del cliente muestra los datos devueltos en la página web creando elementos DOM basados en los datos JSON. También tengo # 3 trabajando desde el punto de vista del servicio web, lo que significa que creará y devolverá un archivo binario si se le dan los parámetros JSON correctos. Pero no estoy seguro de la mejor manera de lidiar con el n. ° 3 en el código JavaScript del cliente.
¿Es posible recuperar un archivo descargable de una llamada ajax como esta? ¿Cómo consigo que el navegador descargue y guarde el archivo?
$.ajax({
type: "POST",
url: "/services/test",
contentType: "application/json",
data: JSON.stringify({category: 42, sort: 3, type: "pdf"}),
dataType: "json",
success: function(json, status){
if (status != "success") {
log("Error loading data");
return;
}
log("Data loaded!");
},
error: function(result, status, err) {
log("Error loading data");
return;
}
});
El servidor responde con los siguientes encabezados:
Content-Disposition:attachment; filename=export-1282022272283.pdf
Content-Length:5120
Content-Type:application/pdf
Server:Jetty(6.1.11)
Otra idea es generar el PDF y almacenarlo en el servidor y devolver JSON que incluye una URL al archivo. Luego, emita otra llamada en el controlador de éxito de ajax para hacer algo como lo siguiente:
success: function(json,status) {
window.location.href = json.url;
}
Pero hacer eso significa que necesitaría hacer más de una llamada al servidor, y mi servidor necesitaría construir archivos descargables, almacenarlos en algún lugar y luego limpiar periódicamente esa área de almacenamiento.
Debe haber una manera más simple de lograr esto. Ideas?
EDITAR: después de revisar los documentos por $ .ajax, veo que el tipo de datos de respuesta solo puede ser uno xml, html, script, json, jsonp, text
, por lo que supongo que no hay forma de descargar directamente un archivo usando una solicitud ajax, a menos que inserte el archivo binario al usar Esquema de URI de datos como se sugiere en la respuesta @VinayC (que no es algo que quiera hacer).
Entonces supongo que mis opciones son:
No use ajax y, en su lugar, envíe una publicación de formulario e incruste mis datos JSON en los valores del formulario. Probablemente necesitaría meterse con iframes ocultos y demás.
No use ajax y, en su lugar, convierta mis datos JSON en una cadena de consulta para crear una solicitud GET estándar y establecer window.location.href en esta URL. Es posible que necesite usar event.preventDefault () en mi controlador de clics para evitar que el navegador cambie de la URL de la aplicación.
Use mi otra idea anterior, pero mejorada con sugerencias de la respuesta @naikus. Envíe la solicitud AJAX con algún parámetro que permita que el servicio web sepa que se está llamando a través de una llamada ajax. Si se llama al servicio web desde una llamada ajax, simplemente devuelva JSON con una URL al recurso generado. Si se llama directamente al recurso, devuelva el archivo binario real.
Cuanto más lo pienso, más me gusta la última opción. De esta forma puedo recuperar información sobre la solicitud (tiempo de generación, tamaño del archivo, mensajes de error, etc.) y puedo actuar sobre esa información antes de comenzar la descarga. La desventaja es la administración adicional de archivos en el servidor.
¿Alguna otra forma de lograr esto? ¿Algún pros / contras de estos métodos que debo tener en cuenta?
url = 'http://localhost/file.php?file='+ $('input').val(); window.open(url);
La forma fácil de obtener los mismos resultados. Pon el encabezado en el archivo php. No es necesario enviar ningún ajax ni recibir solicitudes