La mise en cache inattendue des résultats AJAX dans IE8

135

J'ai un problème sérieux avec les résultats de la mise en cache d'Internet Explorer à partir d'une requête JQuery Ajax.

J'ai un en-tête sur ma page Web qui est mis à jour chaque fois qu'un utilisateur accède à une nouvelle page. Une fois la page chargée, je le fais

$.get("/game/getpuzzleinfo", null, function(data, status) {
    var content = "<h1>Wikipedia Maze</h1>";
    content += "<p class='endtopic'>Looking for <span><a title='Opens the topic you are looking for in a separate tab or window' href='" + data.EndTopicUrl + "' target='_blank'>" + data.EndTopic + "<a/></span></p>";
    content += "<p class='step'>Step <span>" + data.StepCount + "</span></p>";
    content += "<p class='level'>Level <span>" + data.PuzzleLevel.toString() + "</span></p>";
    content += "<p class='startover'><a href='/game/start/" + data.PuzzleId.toString() + "'>Start Over</a></p>";

    $("#wikiheader").append(content);

}, "json");

Il injecte simplement des informations d'en-tête dans la page. Vous pouvez le vérifier en allant sur www.wikipediamaze.com , puis en vous connectant et en commençant un nouveau puzzle.

Dans tous les navigateurs que j'ai testés (Google Chrome, Firefox, Safari, Internet Explorer), cela fonctionne très bien sauf dans IE. Tout est très bien injecté dans IE la première fois, mais après cela, il ne fait même jamais l'appel /game/getpuzzleinfo. C'est comme s'il avait mis en cache les résultats ou quelque chose du genre.

Si je change l'appel à $.post("/game/getpuzzleinfo", ...IE le prend très bien. Mais ensuite, Firefox cesse de fonctionner.

Quelqu'un peut-il s'il vous plaît faire la lumière sur cela pour savoir pourquoi IE met en cache mes $.getappels ajax?

METTRE À JOUR

Selon la suggestion ci-dessous, j'ai changé ma demande ajax en ceci, ce qui a résolu mon problème:

$.ajax({
    type: "GET",
    url: "/game/getpuzzleinfo",
    dataType: "json",
    cache: false,
    success: function(data) { ... }
});
Michée
la source
8
Merci d'avoir posé cette question. Je suis sans voix que ce comportement de navigateur.
jjohn
1
Bonne question et site Web vraiment cool. Bonne idée.
MikeMurko

Réponses:

177

IE est connu pour sa mise en cache agressive des réponses Ajax. Lorsque vous utilisez jQuery, vous pouvez définir une option globale:

$.ajaxSetup({
    cache: false
});

ce qui obligera jQuery à ajouter une valeur aléatoire à la chaîne de requête de requête, empêchant ainsi IE de mettre en cache la réponse.

Notez que si vous avez d'autres appels Ajax en cours là où vous voulez la mise en cache, cela le désactivera également pour ceux-ci. Dans ce cas, passez à la méthode $ .ajax () et activez cette option explicitement pour les requêtes nécessaires.

Voir http://docs.jquery.com/Ajax/jQuery.ajaxSetup pour plus d'informations.

NickFitz
la source
1
Vous pouvez également ajouter un horodatage à la fin de vos URL. Je ne sais pas pourquoi jQuery ne suit pas cette approche à la place.
Eric Johnson du
14
@Eric: c'est ce que fait jQuery en interne - l'option "cache: false" lui dit simplement de le faire.
NickFitz du
Pourquoi jquery ne l'a-t-il pas activé par défaut?
speedplane
Je viens de remarquer que les options de cache ne fonctionnent pas lorsque vous essayez de demander la page d'accueil dans IE 8, avec un appel à /. Modifiez-le en /index.phpou quelle que soit l'URL complète. Ou ajoutez vous-même de faux paramètres comme/?f=f
Hugo Delsing
8

Comme marr75 l'a mentionné, GETles s sont mis en cache.

Il y a plusieurs façons de lutter contre cela. En plus de modifier l'en-tête de la réponse, vous pouvez également ajouter une variable de chaîne de requête générée de manière aléatoire à la fin de l'URL ciblée. De cette façon, IE pensera qu'il s'agit d'une URL différente chaque fois qu'elle est demandée.

Il y a plusieurs façons de faire cela (comme l'utilisation Math.random(), une variation de la date, etc.).

Voici une façon de le faire:

var oDate = new Date();
var sURL = "/game/getpuzzleinfo?randomSeed=" + oDate.getMilliseconds();
$.get(sURL, null, function(data, status) {
    // your work
});
À M
la source
3

Les obtentions peuvent toujours être mises en cache. Une stratégie qui peut fonctionner est de modifier l'en-tête de la réponse et de dire au client de ne pas mettre en cache les informations ou d'expirer le cache très bientôt.

marr75
la source
Ça a l'air d'être une bonne idée. Comment pourrais-je faire ça?
Micah
1
C'est une question chargée, dépend du code côté serveur. Voir l'entrée wikipedia "Liste des en-têtes HTTP" pour quelques conseils. Exemples: Cache-Control: no-cache Expire: Thu, 01 Dec 1994 16:00:00 GMT Fondamentalement, vous devez ajouter ces en-têtes de réponse à votre réponse http. C'est assez simple dans ASP.NET, Ruby et PHP. Recherchez simplement la langue côté serveur que vous utilisez + modifiez les en-têtes de réponse.
marr75
3
De plus, et ce n'est pas du tout une critique de Jquery (j'adore cette bibliothèque), la méthode d'ajout d'un paramètre de chaîne de requête aléatoire est sûre mais impolie pour le client (cela peut les laisser conserver des éléments dans le cache qui ne seront jamais utilisés encore).
marr75
2

Si vous appelez la page ashx, vous pouvez également désactiver la mise en cache sur le serveur avec le code suivant:

context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches); 
Andrej Benedik
la source
1

voici ce que je fais pour les appels ajax:

var url = "/mypage.aspx";
// my other vars i want to add go here
url = url + "&sid=" + Math.random();
// make ajax call

Cela marche plutôt bien pour moi.

Jason
la source
1

NickFitz donne une bonne réponse, mais vous devrez également désactiver la mise en cache dans IE9. Pour cibler uniquement IE8 et IE9, vous pouvez le faire;

<!--[if lte IE 9]>
<script>
    $.ajaxSetup({
        cache: false
    });
</script>
<![endif]-->
Stuart Hallows
la source
0

Les réponses ici sont très utiles pour ceux qui utilisent jQuery ou pour une raison quelconque utilisent directement l'objet xmlHttpRequest ...

Si vous utilisez le proxy de service Microsoft généré automatiquement, ce n'est pas aussi simple à résoudre.

L'astuce consiste à utiliser la méthode Sys.Net.WebRequestManager.add_invokingRequest dans le gestionnaire d'événements pour modifier l'url de la requête:

networkRequestEventArgs._webRequest._url = networkRequestEventArgs._webRequest._url + '&nocache=' + new Date().getMilliseconds(); 

J'ai blogué à ce sujet: http://yoavniran.wordpress.com/2010/04/27/ie-caching-ajax-results-how-to-fix/

poétique
la source
0

Je viens d'écrire un blog sur ce problème précis uniquement en utilisant ExtJS ( http://thecodeabode.blogspot.com/2010/10/cache-busting-ajax-requests-in-ie.html )

Le problème était que j'utilisais un format de réécriture d'url spécifique, je ne pouvais pas utiliser les paramètres de chaîne de requête conventionnels (? Param = valeur), donc j'avais plutôt écrit le paramètre de contournement du cache en tant que variable publiée ..... J'aurais pensé que l'utilisation de variables POST est un peu plus sûre que GET, simplement parce que de nombreux frameworks MVC utilisent le modèle

protocole: // hôte / contrôleur / action / param1 / param2

et ainsi le mappage du nom de la variable à la valeur est perdu, et les paramètres sont simplement empilés ... donc lors de l'utilisation d'un paramètre de buster de cache GET

ie protocole: // hôte / contrôleur / action / param1 / param2 / no_cache122300201

no_cache122300201 peut être confondu avec un paramètre $ param3 qui pourrait avoir une valeur par défaut

c'est à dire

action de fonction publique ($ param1, $ param2, $ param3 = "valeur par défaut") {//..//}

aucune chance que cela se produise avec les busters de cache POSTED

Ben
la source
0

Si vous utilisez ASP.NET MVC, il suffit d'ajouter cette ligne en haut de l'action du contrôleur:

[OutputCache(NoStore=true, Duration = 0, VaryByParam = "None")]
public ActionResult getSomething()
{

}
batmaci
la source
Le comportement en question est du côté du navigateur; cette réponse concerne la mise en cache côté serveur.
Mark Sowul
@MarkSowul Outputcache a 3 options Client, Server et tout. IE utilise OutputCache par défaut, tout ce qui correspond principalement à la mise en cache côté client. Vous pouvez voir plus de détails ici dougwilsonsa.wordpress.com/2011/04/29/…
batmaci
@MarkSowul, vous pouvez également voir la question et la réponse connexes ici. Pensez-vous que c'est aussi du côté du serveur? stackoverflow.com/questions/2653092/…
batmaci
1
Oui, désolé, vous avez raison - je ne savais pas que votre réponse pouvait affecter à la fois le cache côté serveur et le cache côté client.
Mark Sowul
-1

IE est dans ses droits de faire cette mise en cache; pour vous assurer que l'élément n'est pas mis en cache, les en-têtes doivent être définis en conséquence.

Si vous utilisez ASP.NET MVC, vous pouvez écrire un ActionFilter; dans OnResultExecuted, vérifiez filterContext.HttpContext.Request.IsAjaxRequest(). Si tel est le cas, définissez l'en-tête d'expiration de la réponse:filterContext.HttpContext.Response.Expires = -1;

Selon http://www.dashbay.com/2011/05/internet-explorer-caches-ajax/ :

Certaines personnes préfèrent utiliser l 'en - tête Cache - Control: no - cache au lieu d' expire. Voici la différence:
Cache-Control: pas de cache - absolument PAS de mise en cache
Expire: -1 - le navigateur contacte «généralement» le serveur Web pour des mises à jour de cette page via une requête conditionnelle If-Modified-Since. Toutefois, la page reste dans le cache disque et est utilisée dans des situations appropriées sans contacter le serveur Web distant, par exemple lorsque les boutons RETOUR et AVANT sont utilisés pour accéder à l'historique de navigation ou lorsque le navigateur est en mode hors connexion.

Mark Sowul
la source