Hay muchas preguntas sobre el manejo de respuestas AJAX binarias con jQuery como this , this y this . Ninguna ayuda.
Objetivos: (1) determinar dinámicamente si una respuesta contiene datos binarios y manejarlos de manera diferente al texto; (2) analizar encabezados de respuesta; y (3) hacer ambas cosas desde una sola función.
Idealmente, esto se puede hacer desde la función complete , pero la función complete no tiene acceso al objeto XHR. Se supone que jqXHR es un superconjunto del objeto XHR, pero XHR.response está en blanco.
El valor de retorno de $.ajax(settings) contiene los datos binarios, pero el objeto XHR ya no está disponible, por lo que parece que no es posible analizar los encabezados de respuesta.
¿Es posible acceder a la respuesta AJAX binaria dentro de la devolución de llamada completa o acceder al objeto XHR fuera de las funciones de devolución de llamada? los
// Assume @data contains body and URL values. let settings = { url: data.url, method: "post", timeout: 0, contentType: false, processData: false, data: data.body, xhr: function() { // Create XMLHttpRequest object. let xhr = new XMLHttpRequest(); // Handle event for when response headers arrive. xhr.onreadystatechange = function() { if (xhr.readyState == 2) { if (xhr.status == 200) { xhr.responseType = 'blob'; } else { xhr.responseType = 'text'; } } }; return xhr; }, complete: function(xhr, status, error) { // Can access response headers but not binary response here. } }; let response = await $.ajax(settings); // @response is blob but cannot access XHR object here.Supongo que estás usando jQuery v1.5+. La devolución de llamada complete quedó obsoleta en favor de always , que incluye el cuerpo de la respuesta. Podría obtenerlo, junto con los encabezados de respuesta, en una sola función haciendo algo como:
$.ajax({ url: 'https://static.wikia.nocookie.net/5dabc4c4-7cdb-438d-ba57-6b09afffcbb4', method: 'get', }) .always((responseBody, responseStatus, xhr) => { // You don't need this check when using .done() if (responseStatus === 'success') { if (xhr.getResponseHeader('content-type').startsWith('image')) { processImage(responseBody) } } })Esto también debería funcionar en tu ejemplo. Déjame saber si eso funcionó.
No sé si está limitado por alguna versión arcaica de jQuery, pero en realidad puede hacer todo eso.
El valor de retorno de $.ajax(settings) contiene los datos binarios, pero el objeto XHR ya no está disponible, por lo que parece que no es posible analizar los encabezados de respuesta.
Técnicamente , no. El valor de retorno de $.ajax(settings) es el objeto jqXHR, por lo que puede acceder al mismo objeto que obtiene dentro de las devoluciones de llamada. En su código, está utilizando el patrón async/await y, por lo tanto, no puede acceder al objeto jqXHR. pero puedes hacerlo
let jqXHR = $.ajax(settings); jqXHR.then((response) => { console.log(response); console.log(res.getAllResponseHeaders()); });De esta forma, obtendrá tanto el objeto jqXHR como el objeto de respuesta.
Idealmente, esto se puede hacer desde la función completa, pero la función completa no tiene acceso al objeto XHR. Se supone que jqXHR es un superconjunto del objeto XHR, pero XHR.response está en blanco.
Porque estás accediendo a él en el momento equivocado. Para que se complete la propiedad de response , debe esperar hasta readyState 4 en lugar de 2 . Consulte XHR readyState .
Por otra parte, también puede obtener el objeto de respuesta dentro de la devolución de llamada completa. Simplemente trate el parámetro de devolución de llamada xhr de la misma manera que lo haría con la respuesta $.ajax(settings) .
complete: function(xhr, status, error) { res.then((response) => { console.log(response); console.log(res.getAllResponseHeaders()); }); }Si está utilizando las versiones más nuevas de jQuery (supongo que las últimas 2-3 años), incluso puede escribir este código ordenado
complete: async function (xhr, status, error) { console.log(xhr.getAllResponseHeaders()); console.log(await xhr); }Y si literalmente necesitas el objeto XHR, también puedes hacer este truco.
let xhr; let settings = { //rest of things xhr: function () { return xhr = new XMLHttpRequest(); } }; let jqXHR = $.ajax(settings); xhr.onreadystatechange = function() { if (xhr.readyState == 2) { if (xhr.status == 200) { xhr.responseType = 'blob'; } else { xhr.responseType = 'text'; } } }; let response = await jqXHR; console.log(response);Para determinar dinámicamente la respuesta, es más conveniente usar la función de success en lugar de always o complete (estas también se ejecutarán en caso de error). En él, obtiene el objeto jqXHR y puede leer el tipo de datos que se devolvió. Después de determinar que es binario (en el código a continuación, es image/png ), puede convertir la respuesta de texto a binario y, opcionalmente, colocarlo en un Blob . Al igual que:
let data = { url: "https://www.gravatar.com/avatar/cc0c5253923613abd592330ed8adb3a0?s=48&d=identicon&r=PG", body: {} } let settings = { url: data.url, method: "post", timeout: 0, contentType: false, processData: false, data: data.body, success: function(response, status, jqXHR) { var type = jqXHR.getResponseHeader('content-type'); console.log(response); console.log(type); if(type === 'image/png'){ var output = []; for (var i = 0; i < response.length; i++) { output.push( response[i].charCodeAt(0).toString(2) + " "); } output = new Blob(output, {type : type}); console.log(output); } else{ console.log('type is not image/png'); } }, error: function(jqXHR, textStatus, errorThrown) { console.log("an error was encountered", errorThrown); } }; $.ajax(settings); <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>