por leer externo estructura enviar ejemplos ejemplo crear con archivo javascript jquery ajax rest

leer - JavaScript/jQuery para descargar archivos a través de POST con datos JSON



leer json externo con javascript (12)

Con HTML5, puedes crear un ancla y hacer clic en él. No hay necesidad de agregarlo al documento como un niño.

const a = document.createElement(''a''); a.download = ''''; a.href = urlForPdfFile; a.click();

Todo listo.

Si desea tener un nombre especial para la descarga, simplemente páselo en el atributo de download :

const a = document.createElement(''a''); a.download = ''my-special-name.pdf''; a.href = urlForPdfFile; a.click();

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:

  1. Envíe un POST que contenga datos JSON a una URL REST.
  2. Si la solicitud especifica una respuesta JSON, se devuelve JSON.
  3. 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 mediante la creación de 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 cuál es la mejor manera de lidiar con el # 3 en el código javascript del cliente.

¿Es posible recuperar un archivo descargable de una llamada ajax como esta? ¿Cómo consigo el navegador para descargar y guardar 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 incluya una URL al archivo. Luego, emita otra llamada en el controlador de éxito ajax para hacer algo como lo siguiente:

success: function(json,status) { window.location.href = json.url; }

Pero hacerlo significa que necesitaría hacer más de una llamada al servidor, y mi servidor tendría que crear 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 la respuesta dataType solo puede ser una de xml, html, script, json, jsonp, text , así que supongo que no hay manera de descargar directamente un archivo usando un Solicitud de ajax, a menos que incruste el archivo binario en el uso del esquema URI de datos como se sugiere en la respuesta @VinayC (que no es algo que quiera hacer).

Así que supongo que mis opciones son:

  1. No utilice ajax y, en su lugar, envíe una publicación de formulario e incruste mis datos JSON en los valores de formulario. Probablemente tendría que meterse con iframes ocultos y tal.

  2. No use ajax y, en cambio, 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 deba usar event.preventDefault () en mi controlador de clic para evitar que el navegador cambie de la URL de la aplicación.

  3. Use mi otra idea anterior, pero mejorada con sugerencias de la respuesta @naikus. Envíe la solicitud AJAX con algún parámetro que le permita al servicio web saber 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 el recurso se llama directamente, devuelva el archivo binario real.

Cuanto más lo pienso, más me gusta la última opción. De esta manera puedo obtener información sobre la solicitud (tiempo para generar, tamaño del archivo, mensajes de error, etc.) y puedo actuar sobre esa información antes de iniciar la descarga. El inconveniente es la gestión adicional de archivos en el servidor.

¿Alguna otra forma de lograr esto? ¿Cuáles son las ventajas y desventajas de estos métodos que debo conocer?


Creo que el mejor enfoque es utilizar una combinación. Su segundo enfoque parece ser una solución elegante en la que participan los navegadores.

Así que dependiendo de cómo se haga la llamada. (ya sea un navegador o una llamada de servicio web) puede usar una combinación de los dos, enviando una URL al navegador y enviando datos sin procesar a cualquier otro cliente de servicio web.


En definitiva, no hay forma más sencilla. Necesita hacer otra solicitud de servidor para mostrar el archivo PDF. Sin embargo, hay pocas alternativas, pero no son perfectas y no funcionarán en todos los navegadores:

  1. Mira el esquema de URI de datos . Si los datos binarios son pequeños, quizás pueda usar javascript para abrir los datos de paso de la ventana en URI.
  2. La única solución de Windows / IE sería tener el control .NET o FileSystemObject para guardar los datos en el sistema de archivos local y abrirlos desde allí.

Ha pasado un tiempo desde que se hizo esta pregunta, pero tuve el mismo desafío y quiero compartir mi solución. Utiliza elementos de las otras respuestas, pero no pude encontrarlo en su totalidad. No utiliza un formulario o un iframe, pero requiere un par post / get request. En lugar de guardar el archivo entre las solicitudes, guarda los datos de la publicación. Parece ser a la vez simple y eficaz.

cliente

var apples = new Array(); // construct data - replace with your own $.ajax({ type: "POST", url: ''/Home/Download'', data: JSON.stringify(apples), contentType: "application/json", dataType: "text", success: function (data) { var url = ''/Home/Download?id='' + data; window.location = url; }); });

servidor

[HttpPost] // called first public ActionResult Download(Apple[] apples) { string json = new JavaScriptSerializer().Serialize(apples); string id = Guid.NewGuid().ToString(); string path = Server.MapPath(string.Format("~/temp/{0}.json", id)); System.IO.File.WriteAllText(path, json); return Content(id); } // called next public ActionResult Download(string id) { string path = Server.MapPath(string.Format("~/temp/{0}.json", id)); string json = System.IO.File.ReadAllText(path); System.IO.File.Delete(path); Apple[] apples = new JavaScriptSerializer().Deserialize<Apple[]>(json); // work with apples to build your file in memory byte[] file = createPdf(apples); Response.AddHeader("Content-Disposition", "attachment; filename=juicy.pdf"); return File(file, "application/pdf"); }


Hay una forma más simple, crear un formulario y publicarlo, esto corre el riesgo de restablecer la página si el tipo de mimo de retorno es algo que un navegador abriría, pero para csv y tal es perfecto

Ejemplo requiere subrayado y jQuery

var postData = { filename:filename, filecontent:filecontent }; var fakeFormHtmlFragment = "<form style=''display: none;'' method=''POST'' action=''"+SAVEAS_PHP_MODE_URL+"''>"; _.each(postData, function(postValue, postKey){ var escapedKey = postKey.replace("//", "////").replace("''", "/'"); var escapedValue = postValue.replace("//", "////").replace("''", "/'"); fakeFormHtmlFragment += "<input type=''hidden'' name=''"+escapedKey+"'' value=''"+escapedValue+"''>"; }); fakeFormHtmlFragment += "</form>"; $fakeFormDom = $(fakeFormHtmlFragment); $("body").append($fakeFormDom); $fakeFormDom.submit();

Para cosas como html, texto y demás, asegúrese de que el mimetype sea algo como application / octet-stream

código php

<?php /** * get HTTP POST variable which is a string ?foo=bar * @param string $param * @param bool $required * @return string */ function getHTTPPostString ($param, $required = false) { if(!isset($_POST[$param])) { if($required) { echo "required POST param ''$param'' missing"; exit 1; } else { return ""; } } return trim($_POST[$param]); } $filename = getHTTPPostString("filename", true); $filecontent = getHTTPPostString("filecontent", true); header("Content-type: application/octet-stream"); header("Content-Disposition: attachment; filename=/"$filename/""); echo $filecontent;


He estado despierto durante dos días intentando averiguar cómo descargar un archivo usando jquery con ajax call. Todo el apoyo que obtuve no pudo evitar mi situación hasta que probé esto.

Lado del cliente

function exportStaffCSV(t) { var postData = { checkOne: t }; $.ajax({ type: "POST", url: "/Admin/Staff/exportStaffAsCSV", data: postData, success: function (data) { SuccessMessage("file download will start in few second.."); var url = ''/Admin/Staff/DownloadCSV?data='' + data; window.location = url; }, traditional: true, error: function (xhr, status, p3, p4) { var err = "Error " + " " + status + " " + p3 + " " + p4; if (xhr.responseText && xhr.responseText[0] == "{") err = JSON.parse(xhr.responseText).Message; ErrorMessage(err); } }); }

Lado del servidor

[HttpPost] public string exportStaffAsCSV(IEnumerable<string> checkOne) { StringWriter sw = new StringWriter(); try { var data = _db.staffInfoes.Where(t => checkOne.Contains(t.staffID)).ToList(); sw.WriteLine("/"First Name/",/"Last Name/",/"Other Name/",/"Phone Number/",/"Email Address/",/"Contact Address/",/"Date of Joining/""); foreach (var item in data) { sw.WriteLine(string.Format("/"{0}/",/"{1}/",/"{2}/",/"{3}/",/"{4}/",/"{5}/",/"{6}/"", item.firstName, item.lastName, item.otherName, item.phone, item.email, item.contact_Address, item.doj )); } } catch (Exception e) { } return sw.ToString(); } //On ajax success request, it will be redirected to this method as a Get verb request with the returned date(string) public FileContentResult DownloadCSV(string data) { return File(new System.Text.UTF8Encoding().GetBytes(data), System.Net.Mime.MediaTypeNames.Application.Octet, filename); //this method will now return the file for download or open. }

Buena suerte.


He estado jugando con otra opción que usa blobs. Me las arreglé para descargar documentos de texto y descargué los PDF (sin embargo, están dañados).

Usando la API de blob podrás hacer lo siguiente:

$.post(/*...*/,function (result) { var blob=new Blob([result]); var link=document.createElement(''a''); link.href=window.URL.createObjectURL(blob); link.download="myFileName.txt"; link.click(); });

Esto es IE 10+, Chrome 8+, FF 4+. Ver https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL

Solo descargará el archivo en Chrome, Firefox y Opera. Esto utiliza un atributo de descarga en la etiqueta de anclaje para forzar al navegador a descargarlo.


La solución de letronje solo funciona para páginas muy simples. document.body.innerHTML += toma el texto HTML del cuerpo, agrega el iframe HTML y establece el valor interno de la página a esa cadena. Esto eliminará todos los enlaces de eventos que tenga su página, entre otras cosas. Crea un elemento y usa appendChild en appendChild lugar.

$.post(''/create_binary_file.php'', postData, function(retData) { var iframe = document.createElement("iframe"); iframe.setAttribute("src", retData.url); iframe.setAttribute("style", "display: none"); document.body.appendChild(iframe); });

O usando jQuery

$.post(''/create_binary_file.php'', postData, function(retData) { $("body").append("<iframe src=''" + retData.url+ "'' style=''display: none;'' ></iframe>"); });

Lo que esto hace en realidad: realice una publicación en /create_binary_file.php con los datos en la variable postData; Si esa publicación se completa con éxito, agregue un nuevo iframe al cuerpo de la página. El supuesto es que la respuesta de /create_binary_file.php incluirá un valor ''url'', que es la URL desde donde se puede descargar el archivo PDF / XLS / etc generado. Agregar un iframe a la página que hace referencia a esa URL dará como resultado que el navegador promocione al usuario para descargar el archivo, asumiendo que el servidor web tiene la configuración de tipo mime adecuada.


No es completamente una respuesta a la publicación original, sino una solución rápida y sucia para publicar un objeto json en el servidor y generar dinámicamente una descarga.

JQuery del lado del cliente:

var download = function(resource, payload) { $("#downloadFormPoster").remove(); $("<div id=''downloadFormPoster'' style=''display: none;''><iframe name=''downloadFormPosterIframe''></iframe></div>").appendTo(''body''); $("<form action=''" + resource + "'' target=''downloadFormPosterIframe'' method=''post''>" + "<input type=''hidden'' name=''jsonstring'' value=''" + JSON.stringify(payload) + "''/>" + "</form>") .appendTo("#downloadFormPoster") .submit(); }

... y luego descodificar la cadena json en el lado del servidor y configurar los encabezados para descargar (ejemplo de PHP):

$request = json_decode($_POST[''jsonstring'']), true); header(''Content-Type: application/csv''); header(''Content-Disposition: attachment; filename=export.csv''); header(''Pragma: no-cache'');


Otro enfoque, en lugar de guardar el archivo en el servidor y recuperarlo, es usar .NET 4.0+ ObjectCache con una corta caducidad hasta la segunda Acción (en cuyo momento se puede volcar definitivamente). La razón por la que quiero usar JQuery Ajax para hacer la llamada es que es asíncrono. La creación de mi archivo PDF dinámico lleva bastante tiempo, y durante ese tiempo muestro un cuadro de diálogo con el botón de giro ocupado (también permite realizar otro trabajo). El enfoque de utilizar los datos devueltos en el "éxito:" para crear un Blob no funciona de manera confiable. Depende del contenido del archivo PDF. Es fácilmente corrompido por los datos en la respuesta, si no es completamente textual, que es todo lo que Ajax puede manejar.


Sé que este tipo de viejo, pero creo que he encontrado una solución más elegante. Tuve exactamente el mismo problema. El problema que estaba teniendo con las soluciones sugeridas era que todos requerían que el archivo se guardara en el servidor, pero no quería guardar los archivos en el servidor, ya que presentaba otros problemas (seguridad: el archivo podía acceder al archivo. usuarios no autenticados, limpieza: cómo y cuándo deshacerse de los archivos). Y al igual que usted, mis datos eran objetos JSON anidados complejos que serían difíciles de poner en un formulario.

Lo que hice fue crear dos funciones de servidor. La primera validó los datos. Si hubiera un error, sería devuelto. Si no fue un error, devolví todos los parámetros serializados / codificados como una cadena base64. Luego, en el cliente, tengo un formulario que solo tiene una entrada oculta y se publica en una segunda función de servidor. Establecí la entrada oculta a la cadena base64 y envié el formato. La segunda función del servidor decodifica / deserializa los parámetros y genera el archivo. El formulario podría enviarse a una nueva ventana o un iframe en la página y el archivo se abrirá.

Hay un poco más de trabajo involucrado, y quizás un poco más de procesamiento, pero en general, me siento mucho mejor con esta solución.

El código está en C # / MVC

public JsonResult Validate(int reportId, string format, ReportParamModel[] parameters) { // TODO: do validation if (valid) { GenerateParams generateParams = new GenerateParams(reportId, format, parameters); string data = new EntityBase64Converter<GenerateParams>().ToBase64(generateParams); return Json(new { State = "Success", Data = data }); } return Json(new { State = "Error", Data = "Error message" }); } public ActionResult Generate(string data) { GenerateParams generateParams = new EntityBase64Converter<GenerateParams>().ToEntity(data); // TODO: Generate file return File(bytes, mimeType); }

en el cliente

function generate(reportId, format, parameters) { var data = { reportId: reportId, format: format, params: params }; $.ajax( { url: "/Validate", type: ''POST'', data: JSON.stringify(data), dataType: ''json'', contentType: ''application/json; charset=utf-8'', success: generateComplete }); } function generateComplete(result) { if (result.State == "Success") { // this could/should already be set in the HTML formGenerate.action = "/Generate"; formGenerate.target = iframeFile; hidData = result.Data; formGenerate.submit(); } else // TODO: display error messages }


$scope.downloadSearchAsCSV = function(httpOptions) { var httpOptions = _.extend({ method: ''POST'', url: '''', data: null }, httpOptions); $http(httpOptions).then(function(response) { if( response.status >= 400 ) { alert(response.status + " - Server Error /nUnable to download CSV from POST/n" + JSON.stringify(httpOptions.data)); } else { $scope.downloadResponseAsCSVFile(response) } }) }; /** * @source: https://github.com/asafdav/ng-csv/blob/master/src/ng-csv/directives/ng-csv.js * @param response */ $scope.downloadResponseAsCSVFile = function(response) { var charset = "utf-8"; var filename = "search_results.csv"; var blob = new Blob([response.data], { type: "text/csv;charset="+ charset + ";" }); if (window.navigator.msSaveOrOpenBlob) { navigator.msSaveBlob(blob, filename); // @untested } else { var downloadContainer = angular.element(''<div data-tap-disabled="true"><a></a></div>''); var downloadLink = angular.element(downloadContainer.children()[0]); downloadLink.attr(''href'', window.URL.createObjectURL(blob)); downloadLink.attr(''download'', "search_results.csv"); downloadLink.attr(''target'', ''_blank''); $document.find(''body'').append(downloadContainer); $timeout(function() { downloadLink[0].click(); downloadLink.remove(); }, null); } //// Gets blocked by Chrome popup-blocker //var csv_window = window.open("","",""); //csv_window.document.write(''<meta name="content-type" content="text/csv">''); //csv_window.document.write(''<meta name="content-disposition" content="attachment; filename=data.csv"> ''); //csv_window.document.write(response.data); };