Cómo hacer que Microsoft XmlHttpRequest cumpla con la directiva de control de caché
msxml cache-control (10)
La desventaja de eso es que inunda el caché con varias copias del mismo contenido. Puede tratarse de piratear a los agentes http con errores, pero una solución real es trabajar con mecanismos de almacenamiento en caché, en lugar de contra ellos. -
Estoy de acuerdo en que esto no es ideal y no es realmente una solución, pero Mozilla realmente recomienda esto como una solución alternativa, por lo que creo que no debe ser demasiado terrible - https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest
Además, estaba arrancándome el pelo tratando de resolver esto. He tenido que confiar en que mis usuarios borren su navegador (algo que siempre olvidan hacer). Así que esto es una bendición para mí!
Estoy emitiendo una solicitud utilizando el objeto XmlHttpRequest de MSXML:
IXMLHttpRequest http = new XmlHttpRequest();
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.send();
Y el send
correctamente, y obtengo mis datos xml.
Excepto que XmlHttpRequest
no llegó a la red (puedo ver que no se emitió ninguna solicitud de http real). Y Process Monitor muestra que el archivo está siendo servido desde mi caché:
Así que quiero indicar al agente de usuario XmlHttpRequest
que cualquier contenido en caché que tenga más de 0 segundos es demasiado antiguo. La forma estándar de hacerlo es agregar un encabezado de solicitud:
Cache-Control: max-age=0
a la solicitud de envío:
http = new XmlHttpRequest();
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "max-age=0");
http.send();
Y el send
correctamente, y obtengo mis datos xml.
Excepto que XmlHttpRequest
no llegó a la red (puedo ver que no se emitió ninguna solicitud de http real). Y Process Monitor muestra que el archivo está siendo servido desde mi caché.
Entonces, ¿qué está mal? ¿ max-age
no está haciendo lo que creo que hace?
De RFC 2616 - Protocolo de transferencia de hipertexto, Parte 14: Definiciones de campo de encabezado :
Otras directivas permiten que un agente de usuario modifique el mecanismo básico de caducidad. Estas directivas PUEDEN especificarse en una solicitud:
edad máxima
Indica que el cliente está dispuesto a aceptar una respuesta cuya edad no es mayor que el tiempo especificado en segundos. A menos que también se incluya la directiva máxima, el cliente no está dispuesto a aceptar una respuesta obsoleta.
Que es exactamente lo que quiero.
¿ Cache-Control: max-age=0
no es exactamente lo que quiero, o es el buggy del objeto XmlHttpRequest
de MSXML?
Actualización uno
Este es el objeto COM MSXML XmlHttpRequest
:
- CLSID: {88d96a0a-f192-11d4-a65f-0040963251e5}
- ProgID: Msxml2.XMLHTTP.6.0
Actualización dos
El cliente agrega la directiva max-age
para que todos los cachés se adhieran. Desde RFC:
El campo de encabezado general de Cache-Control se usa para especificar directivas que DEBEN ser obedecidas por todos los mecanismos de almacenamiento en caché a lo largo de la cadena de solicitud / respuesta . Las directivas especifican el comportamiento destinado a evitar que las memorias caché interfieran negativamente con la solicitud o respuesta. Estas directivas suelen anular los algoritmos de almacenamiento en caché predeterminados. Las directivas de caché son unidireccionales, ya que la presencia de una directiva en una solicitud no implica que la misma directiva deba darse en la respuesta.
La edad máxima no es para el servidor; no tiene sentido para un servidor. Está destinado a todos los sistemas de almacenamiento en caché entre el usuario y el servidor.
Actualización tres
Desde W3C XmlHttpRequest :
Si el agente de usuario implementa un caché HTTP, debe respetar los encabezados de solicitud de
Cache-Control
establecidos porsetRequestHeader()
(por ejemplo,Cache-Control: no-cache
pasa por alto el caché). No debe enviar los encabezados de solicitud deCache-Control
oPragma
automáticamente a menos que el usuario final solicite explícitamente tal comportamiento (por ejemplo, recargando la página).
Siguiendo su ejemplo , intenté usar la directiva no-cache
:
http = new XmlHttpRequest();
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "no-cache");
http.send();
Y el cliente XmlHttpRequest
aún XmlHttpRequest
las solicitudes completamente desde la memoria caché, sin consultar el servidor en absoluto.
El W3C dice que si hay un caché, debe respetar Cache-Control
si se establece a través de setRequestHeader
. XmlHttpRequest de Microsoft no parece cumplir con ese requisito.
¿Podría agregar un parámetro falso al final de su URI que cambia con cada solicitud?
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?requestID=42", False, "", "");
Desafortunadamente, el objeto XMLHttpRequest
fue diseñado de esta manera, porque está basado en WinInet. Además, no se recomienda su uso desde el lado del servidor. Debe usar ServerXMLHttpRequest
, que tiene la misma funcionalidad, pero depende de WinHTTP
lugar. Consulte las FAQ para obtener más información. Una descripción de la documentación de ServerXMLHttp
indica que:
La pila de clientes HTTP ofrece tiempos de actividad más largos. Las funciones de WinInet que no son críticas para las aplicaciones de servidor, como el almacenamiento en caché de URL, el descubrimiento automático de servidores proxy, la fragmentación de HTTP / 1.1, la compatibilidad sin conexión y la compatibilidad con los protocolos Gopher y FTP no se incluyen en el nuevo subconjunto de HTTP.
Esto significa que en lugar de usar XmlHttpRequest :
IXMLHTTPRequest http = CreateComObject("Msxml2.XMLHTTP.6.0"); http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "max-age=0");
http.send();
puedes usar ServerXmlHttpRequest :
IXMLHTTPRequest http = CreateComObject("Msxml2.ServerXMLHTTP");
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "max-age=0");
http.send();
o WinHttpRequest :
IWinHttpRequest http = CreateComObject("WinHttp.WinHttpRequest.5.1");
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "max-age=0");
http.send();
Descubrí que usar el encabezado If-None-Match
, especificando un valor que no coincida con la ETag
de la última solicitud, funcionará.
P.ej:
req.open("GET", url, false);
req.setRequestHeader("If-None-Match", "/"doesnt-match-anything/"");
req.send();
Esto podría o no requerir que las respuestas incluyan un ETag
. (Solo lo probé con un servicio que incluye un valor de ETag
en cada respuesta).
Este encabezado es para el servidor, y como el navegador no hace ningún evento, no sirve de nada.
Un truco fácil es cargar la página de esta manera:
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?"+Math.random(), False, "", "");
Esto me estaba volviendo loco. Este hilo de SO se acercó más a proporcionar una respuesta. Desafortunadamente, durante la prueba ninguno de ellos realmente funcionó para mí. La única solución que encontré que probé para funcionar correctamente fue la configuración:
Encabezado Pragma: no-caché
Espero que salve a otros con dolores de cabeza en IE.
Por cierto, este hilo de es excelente para aclarar la diferencia entre Pragma y Cache-control: ¿ Diferencia entre Pragma y Cache-control headers?
Intenta enviar ''cache-control: private'' como encabezado. Esto funcionó para mí:
var request = new XMLHttpRequest();
request.open("GET", ''http://myurl.com'' , false);
request.setRequestHeader("cache-control", "private");
Estoy escribiendo una aplicación HTML y Javascript para Windows 8 donde se ignoran y no-cache y max-age. Para mí lo anterior funciona bien.
No estaba familiarizado con el encabezado, así que hice un poco de investigación sobre el control de caché: privado ...
Indicates that all or part of the response message is intended for a single user and MUST NOT be cached by a shared cache, such as a proxy server.
¿ De qué es Cache-Control: privado? y http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
Así que, básicamente, esto nunca creará una entrada de caché y, por lo tanto, no agrega entradas de caché que sabemos son superfluas, como con un parámetro de número aleatorio de ''caché-destructor''.
Mi solución rápida y sucia en un cliente estándar de Windows era
- Opciones de internet
- general
- Configuración del historial de navegación
- Compruebe si hay nuevas versiones de las páginas almacenadas:
tickle "(x) Cada vez que visito la página web"
Ahora mi objeto Msxml2.XMLHTTP.x.0 ya no usa el caché ...
Para la antigua biblioteca msxml, uso un valor generado aleatoriamente para la dirección uri, por ejemplo:
http: // youlink? mysession = random_number
Wojtek
Uso esto para una sesión de keep-alive y funciona muy bien.
El truco es usar el encabezado "If-Modified-Since" con un valor más nuevo que el almacenado en caché por el navegador.
g_AjaxObj.onreadystatechange = function() { if(g_AjaxObj.readyState === 4) { AjaxOnComplete_("KeepAlive"); }};
g_AjaxObj.open(''GET'', URL, true);
g_AjaxObj.setRequestHeader("If-Modified-Since", new Date().toUTCString());
g_AjaxObj.send(null);