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) { ... }
});

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.


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
});

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.


Ç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); 

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.


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]-->

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/


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


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()
{

}

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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.