Comment faire Microsoft XmlHttpRequest honor cache control directive

j'émets une demande en utilisant XMLHttpRequest "de MSXML objet:

IXMLHttpRequest http = new XmlHttpRequest();
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.send();

et le send réussit, et je reçois mes données xml.

sauf que XmlHttpRequest n'a pas réellement atteint le réseau (je peux voir qu'il n'y a pas de requête http réelle émise). Et Process Monitor montre que le fichier est effectivement servi depuis mon cache:

enter image description here

donc je veux donner des instructions à l'agent utilisateur XmlHttpRequest que tout contenu mis en cache plus de 0 secondes est trop vieux. Le standard way pour ce faire est d'ajouter un en-tête de requête:

Cache-Control: max-age=0

à la demande d'envoi:

http = new XmlHttpRequest();
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "max-age=0");
http.send();

et le send réussit, et je reçois mes données xml.

sauf que XmlHttpRequest n'a pas réellement atteint le réseau (Je ne peux voir là aucune requête http réelle émettre.) Et Process Monitor montre que le fichier est effectivement servi depuis mon cache.

alors qu'est-ce qui ne va pas? Est-ce que max-age ne fait pas ce que je pense qu'il fait?

à Partir de RFC 2616 - Protocole de Transfert Hypertexte, la Partie 14: Champ d'en-Tête Définitions de :

D'autres directives permettent à un agent utilisateur de modifier le mécanisme d'expiration de base. Ces directives peuvent être spécifiées demande:

max-age

Indique que le client est prêt à accepter une réponse dont l'âge ne dépasse pas le temps déterminé en quelques secondes. A moins que max-stale directive est également inclus, le client n'est pas disposé à accepter un rassis réponse.

C'est exactement ce que je veux.

Est Cache-Control: max-age=0 pas exactement ce que je veux, ou est MSXML XmlHttpRequest objet buggy?

Mise À Jour D'Un

C'est le MSXML XmlHttpRequest objet COM:

  • CLSID: {88d96a0a-f192-11d4-a65f-0040963251e5}
  • ProgID: Msxml2.XMLHTTP.6.0

Mettre À Jour Les Deux

la directive max-age est ajoutée par le client pour que tous les cache y adhèrent. De RFC:

Le Cache-Control généralités-champ d'en-tête est utilisé pour spécifier des directives doit être obéi par toute la mise en cache mécanismes le long de la requête/réponse la chaîne . Les directives spécifient le comportement destiné à empêcher les caches de négativement interférant avec la demande ou de la réponse. Ces directives généralement, outrepasser la mise en cache par défaut algorithme. Les directives Cache sont: unidirectionnel en ce que la présence de une directive dans une requête ne implique que la même directive est de être donné dans la réponse.

max-age n'est pas pour le serveur; cela n'a aucun sens pour un serveur. Il est destiné à tous les systèmes de mise en cache entre l'utilisateur et le serveur.

Mise À Jour De Trois

From W3C XmlHttpRequest :

si l'agent utilisateur implémente un cache HTTP il devrait respecter Cache-Control en-têtes de demande définis par les setRequestHeader() (par exemple:, Cache-Control: no-cache contourne le cache.) ne doit pas envoyer Cache-Control ou Pragma en-têtes de demande automatiquement, sauf si l'utilisateur final demande explicitement un tel comportement (par exemple, par le rechargement de la page).

suivant leur exemple , j'ai essayé d'utiliser la no-cache directive:

http = new XmlHttpRequest();
http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml", False, "", "");
http.setRequestHeader("Cache-Control", "no-cache");
http.send();

et le client XmlHttpRequest demande complètement depuis le cache, sans interroger le serveur.

le W3C dit que s'il y a une cache, elle doit honorer Cache-Control si elle est définie par setRequestHeader . XMLHttpRequest de Microsoft ne semble pas respecter cette exigence.

29
demandé sur Ian Boyd 2011-03-08 19:42:57

10 réponses

malheureusement, l'objet XMLHttpRequest a été conçu de cette façon, car il est basé sur WinInet. De plus, il n'est pas recommandé de l'utiliser du côté du serveur. Vous devez utiliser ServerXMLHttpRequest , qui a la même fonctionnalité, mais dépend de WinHTTP à la place. Voir le FAQ pour plus d'informations. Une description tirée de la documentation ServerXMLHttp indique que:

le La pile de clients HTTP offre plus sans interruption. Les fonctionnalités de WinInet qui ne sont pas critique pour les applications de serveur, tels comme le cache D'URL, auto-découverte de serveurs mandataires, chunking HTTP/1.1, prise en charge hors connexion, et de soutien pour Les protocoles Gopher et FTP ne sont pas inclus dans le nouveau sous-ensemble HTTP.

cela signifie que plutôt que d'utiliser 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();

vous pouvez utiliser 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();

ou 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();
16
répondu Garett 2016-03-04 20:30:54

j'ai trouvé que l'utilisation de If-None-Match en-tête, spécifiant une valeur qui ne correspond pas au ETag de la dernière requête fonctionnera.

par exemple:

req.open("GET", url, false);
req.setRequestHeader("If-None-Match", "\"doesnt-match-anything\"");
req.send();

cela pourrait exiger ou non que les réponses comprennent un ETag . (Je l'ai seulement essayé avec un service qui inclut une valeur ETag dans chaque réponse.)

5
répondu J. Mullaney 2012-10-27 00:26:50

pouvez-vous ajouter un paramètre bidon à la fin de votre URI qui change avec chaque requête?

http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?requestID=42", False, "", "");
1
répondu blue t-shirt 2011-03-08 16:43:54

Je l'utilise pour une session "keep-alive" et ça marche très bien.

L'astuce consiste à utiliser l'en-tête "If-Modified-Since" avec une valeur plus récente que celle mise en cache par le navigateur.

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);
1
répondu tranzitwww 2011-11-07 18:07:57

ma solution rapide et sale à un client Windows standard était

- Options Internet

- Général

- paramètres D'historique de navigation

- Vérifier les Versions plus récentes des pages stockées:

tickle "x) chaque fois que je visite la page Web "

Maintenant mon Msxml2.XMLHTTP.x.0 0 Objet n'utilisez plus le Cache ...

1
répondu anonymous 2014-05-07 16:08:19

envoyer 'cache-control: private' comme un en-tête. Cela a fonctionné pour moi:

var request = new XMLHttpRequest();
request.open("GET", 'http://myurl.com' , false); 

request.setRequestHeader("cache-control", "private");

je suis en train d'écrire une application HTML & Javascript pour Windows 8 où et à la fois no-cache et max-age sont ignorées. Pour moi, le ci-dessus fonctionne très bien.

Je ne connaissais pas l'en-tête alors j'ai fait un petit détour sur cache-control: private...

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.

à Partir de qu'est-Ce que Cache-Control: private? et http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

donc, fondamentalement, cela ne créera jamais une entrée de cache et donc n'ajoute pas d'entrées de cache que nous savons superflues, comme avec un paramètre de nombre aléatoire 'cache-buster'.

1
répondu Matt 2017-05-23 11:53:59

cet en-tête est pour le serveur, et comme le navigateur ne fait pas d'événement faire n'importe quelle demande, son inutile.

Un truc facile est de charger la page comme ceci :

http.open("GET", "http://www.bankofcanada.ca/stat/fx-xml.xml?"+Math.random(), False, "", "");
0
répondu jujule 2011-03-08 16:46:01

pour l'ancienne bibliothèque msxml, j'utilise la valeur générée au hasard pour l'adresse uri par exemple:

http://youlink Je ne sais pas.mysession=random_number

wojtek

0
répondu wojtek 2011-09-19 15:34:57

L'inconvénient de cela est que vous inondez la cache avec plusieurs copies de le même contenu. Il pourrait être un hack autour buggy agents http-mais un la vraie solution est de travailler avec des mécanismes de cache, plutôt que contre ils. -

Je suis d'accord que ce n'est pas idéal et pas vraiment une solution, mais Mozilla recommande en fait cette solution, donc je me dis que ce ne doit pas être trop terrible - https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest

en plus, je me déchire les cheveux en essayant de résoudre ça. J'ai dû compter sur mes utilisateurs pour nettoyer leur navigateur (ce qu'ils oublient toujours de faire). C'est donc une aubaine pour moi!

0
répondu Sue Smiles 2013-03-11 01:44:17

ça me rendait dingue. C'est donc ce fil qui s'est le plus rapproché de la réponse. Malheureusement, pendant les tests, aucun d'entre eux n'a vraiment travaillé pour moi. La seule solution que j'ai trouvée et qui a été testée pour fonctionner correctement était le réglage:

en-tête Pragma: no-cache

j'espère qu'il sauve d'autres avec des maux de tête IE.

BTW c'est le fil StackOverflow est grand pour faire la lumière sur la différence entre Pragma et Cache-contrôle: Différence entre les en-têtes Pragma et Cache-control?

0
répondu MarkCheshire 2017-05-23 11:46:30