2011-03-02 10 views
40

Cómo verificar si el estado de la cabecera de solicitud jQuery.ajax() es "304 no modificado"?Cómo comprobar si el estado de jQuery.ajax() request header es "304 Not Modified"?

jqXHR.status generalmente devuelve 200, incluso cuando el encabezado solicitado es "304 no modificado".

ifModified:truedoes not help porque rompe la solicitud de datos XHR.

+1

La respuesta corta es no. Sin embargo, este es un posible duplicado de [Determinando qué jQuery .ajax() resuelve una cadena de redireccionamientos a] (http://stackoverflow.com/questions/6767618/determining-what-jquery-ajax-resolves-a-string- of-redirects-to) Aunque no es exactamente la misma pregunta, el concepto es el mismo: la especificación XHR no requiere ninguna notificación de respuestas 3xx. – JAAulde

+0

Vale la pena señalar que no es necesario hacer la verificación de ETag manualmente, desde su javascript, el navegador lo manejará por usted. Entonces, a menos que tenga una razón especial para hacerlo, generalmente no necesita verificar la respuesta 304 – Anentropic

Respuesta

59

Sin manejar los encabezados de caché manualmente, no es posible. Normalmente, 304 respuestas no se ponen a disposición a través de la XHR API:

Por 304 Not Modified respuestas que son el resultado de un agente de usuario genera la solicitud condicional el agente de usuario debe actuar como si el servidor dio una respuesta 200 OK con el contenido apropiado.

jQuery normalmente no sabe que hubo una respuesta 304, porque el navegador le dice mentiras a JavaScript sobre lo que está sucediendo realmente en la red.

Pero hay buenas noticias (tipo de): se puede obtener Ajax para producir una respuesta 304, pero sólo manualmente ajustando el HTTP cache headersIf-Modified-Since o If-None-Match en la solicitud:

El agente de usuario debe Permitir setRequestHeader() para anular la validación automática de caché mediante el establecimiento de encabezados de solicitud (por ejemplo, If-None-Match, If-Modified-Since), en cuyo caso se deben pasar 304 respuestas no modificadas.

Por lo tanto, se puede utilizar un código como:

var xhr = new XMLHttpRequest(); 
xhr.open("GET", "foo.html"); 
xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT"); 
xhr.send(); 

Una dificultad fundamental es , ¿cómo saber qué fecha de última modificación o ETag para enviar? El navegador tiene información de caché que utiliza para enviar solicitudes, pero no compartirá esa información con JavaScript. Afortunadamente, jQuery realiza un seguimiento de los encabezados Last-Modified y ETag de las respuestas de Ajax, por lo que puede usar ifModified:true para que jQuery establezca esos valores de encabezado la próxima vez que envíe una solicitud para ese recurso.

Dos cosas a tener en cuenta sobre esta

:
  • 304 respuestas no transportan datos. Esto es por diseño. La suposición es que si ha elegido usar el almacenamiento en caché, ¡debería tener una copia de los datos que ya están en su caché!Si no obtiene ningún dato del servidor (es decir, porque todavía no tiene esa información), ¿por qué está utilizando el almacenamiento en caché? El almacenamiento en caché debe usarse cuando tiene los datos antiguos disponibles y solo desea datos nuevos; por lo tanto, recuperar datos con un 304 no debería ser un problema.

  • jQuery debe tener una fecha de última modificación o un ETag (para usar con If-None-Match) almacenado de una solicitud anterior. El proceso es el siguiente:

    • Primera tomará: jQuery no tiene información de caché, por lo que no envía If-Modified-Since o If-None-Match. Cuando la respuesta vuelve, el servidor puede anunciar una última modificación de datos o una ETag, que jQuery almacena para su uso futuro.

    • Recuperaciones posteriores: jQuery tiene información de caché de la última recuperación y reenvía esos datos al servidor. Si el recurso no ha cambiado, la solicitud de Ajax obtiene una respuesta 304. Si el recurso ha cambiado, la solicitud de Ajax obtiene una respuesta de 200, junto con la nueva información de caché que jQuery usará para su próxima búsqueda.

    • jQuery no persisten la información de caché (por ejemplo, en las cookies) entre recargas de página, sin embargo. Por lo tanto, la primera recuperación de un recurso después de una recarga de página será nunca sea un 304, porque jQuery no tiene información de caché para enviar (es decir, reiniciamos al caso de "primera búsqueda"). No hay ninguna razón por la cual jQuery no pudo conservar la información de la memoria caché, pero en este momento no es así.

El fondo aquí es que se puede utilizar cabeceras de caché para obtener una respuesta JavaScript 304, pero no se puede acceder propia ETag o fecha de última modificación del navegador de un recurso en particular. Por lo tanto, es posible que el navegador conozca información de almacenamiento en caché sobre un recurso, pero su código JavaScript no. En ese caso, el navegador usará sus encabezados de caché para obtener potencialmente una respuesta 304 real, pero reenvía una respuesta de 200 a su código JavaScript, porque JavaScript no envió ninguna información de caché.

No es posible hacer que las solicitudes de JavaScript 304 se alineen perfectamente con las 304 respuestas reales de la red, porque la información de caché conocida por su navegador y la información de caché conocida por su código JavaScript pueden diferir en formas impredecibles. Sin embargo, obtener 304 solicitudes correctamente la mayor parte del tiempo es suficiente para la mayoría de las necesidades de desarrollo práctico.

Ejemplo

He aquí un breve ejemplo de servidor escrito en Node.js (pero debe ser lo suficientemente simple para un puerto con otros langauges):

require("http").createServer(function (req, res) { 
    console.log(req.headers["if-modified-since"]); 

    // always send Last-Modifed header 
    var lastModDate = "Fri, 13 Feb 2013 13:43:19 GMT"; 
    res.setHeader("Last-Modified", lastModDate); 

    // if the request has a If-Modified-Since header, 
    // and it's newer than the last modification, 
    // then send a 304 response; otherwise send 200 
    if(req.headers["if-modified-since"] && 
    Date.parse(lastModDate) <= Date.parse(req.headers["if-modified-since"])) { 
    console.log("304 -- browser has it cached"); 
    res.writeHead(304, {'Content-Type': 'text/plain'}); 
    res.end(); 
    } else { 
    console.log("200 -- browser needs it fresh"); 
    res.writeHead(200, {'Content-Type': 'text/plain'}); 
    res.end('some content'); 
    } 

}).listen(8080); 

Cuando se ejecuta este servidor, puede cargar la página en su navegador y realizar dos pruebas diferentes en su consola de navegador:

var xhr = new XMLHttpRequest(); 
xhr.open("GET", "/"); 
xhr.send(); 
xhr.onload = function() { console.log(xhr.status); } 

Este script siempre verán una respuesta 200, incluso si el navegador s actualiza un encabezado de solicitud If-Modified-Since y obtiene un 304 (que sucederá a todas las solicitudes después de la primera, después de que el navegador vea el encabezado de respuesta del servidor Last-Modifed).

Por el contrario, este script siempre ver la respuesta 304:

var xhr = new XMLHttpRequest(); 
xhr.open("GET", "/"); 
xhr.setRequestHeader("If-Modified-Since", "Fri, 15 Feb 2013 13:43:19 GMT"); 
xhr.send(); 
xhr.onload = function() { console.log(xhr.status); } 

El guión suministra su propia cabecera If-Modified-Since petición (dos días después de la fecha de última modificación del servidor); no depende de lo que el navegador suministre para If-Modified-Since, y por lo tanto está permitido (según la especificación XHR) ver 304 respuestas.

Por último, este script siempre verá un 200:

var xhr = new XMLHttpRequest(); 
xhr.open("GET", "/"); 
xhr.setRequestHeader("If-Modified-Since", "Fri, 12 Feb 2013 13:43:19 GMT"); 
xhr.send(); 
xhr.onload = function() { console.log(xhr.status); } 

Esto se debe a que la secuencia de comandos utiliza un If-Modified-Since que es anterior a la fecha de última modificación del servidor, por lo que el servidor siempre envía una 200. El servidor no enviará un 304 porque supone que el cliente no tiene una copia almacenada en caché de la versión más reciente (es decir, el cliente anuncia que ha visto cambios desde el 12 de febrero, pero el 13 de febrero hubo un cambio en que el cliente aparentemente no ha visto).

+0

Respuesta correcta. – JAAulde

+0

"El agente de usuario debe permitir que setRequestHeader() anule la validación automática de caché estableciendo encabezados de solicitud (por ejemplo, If-None-Match, If-Modified-Since), en cuyo caso se deben pasar 304 respuestas no modificadas. [RFC2616] " –

+0

@ChristopherJamesCalo Reconozco que mi respuesta anterior fue lamentablemente incompleta: he ampliado considerablemente mi respuesta para hablar sobre el uso de encabezados de caché en JavaScript. – apsillers

-5

Quizás intente esto?

$.ajax({ 
    url: 'your-url', 
    dataType: 'script', 
    complete: function(xhr) { 
     if (xhr.status == 304) return; 
     // or better: if (xhr.status != 200) return; 
     // your code goes here 
    } 
}); 
+3

. No funciona. – Binyamin

+0

XHR 'readsystatechange' no se activa con las respuestas 3xx, por lo que' complete' no se ingresará mientras 'status' sea 304. – JAAulde

-5

abra el inspector de su navegador y le mostrará información sobre la solicitud de AJAX, incluido el estado.

para cromado, haga clic derecho y elija inspeccionar elemento, luego vaya a la pestaña Red.

para firefox, solo use firebug y siga los mismos pasos.

+2

Esto solo ayuda al OP a conocer como un observador humano. Creo que le gustaría que su programa "sepa" y tome decisiones con esa información. – JAAulde

0

también las cabeceras se almacenan en caché si la respuesta viene de la memoria caché. Tomé esto como una oportunidad. Mi servidor envía un encabezado md5 único. Esto no tiene el mismo efecto que? Query = time(). Ahora, en el lado JS, verifique el último encabezado md5 con la corriente. Si recibe el mismo encabezado MD5 que antes, la respuesta proviene de la memoria caché. Olvidé todo sobre JQuery pero vi que es posible establecer y leer encabezados.

<?php 
$oldMD5=filter_input(INPUT_SERVER,'HTTP_CONTENT_MD5',int); 
if(!empty($oldMD5)){ 
    header('Content-MD5: '.(1+(int)$oldMD5)); 
} 
-------------------------------------------------------------- 
<script> 
var oldMD5=0; 
//your Ajax implementation 
Ajax.setRequestHeader('Content-MD5',''+oldMD5); 
var newMD5=parseInt(Ajax.getResponseHeader('Content-MD5'),10); 
if(newMD5 && oldMD5<newMD5,10){ 
    oldMD5=newMD5; 
    //not cached 
}else{ 
    //cached 
} 

Esto es un poco como abuso poco, porque MD5 debe ser un hash para verificar que los datos decodificados 'son los mismos datos que se envía desde la fuente'.

Cuestiones relacionadas