O cache inesperado do AJAX resulta no IE8

135

Estou tendo um problema sério com os resultados de cache do Internet Explorer de uma solicitação JQuery Ajax.

Tenho um cabeçalho na minha página da web que é atualizado toda vez que um usuário navega para uma nova página. Depois que a página é carregada, faço isso

$.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");

Apenas injeta informações do cabeçalho na página. Você pode conferir isso acessando www.wikipediamaze.com e depois fazendo login e iniciando um novo quebra-cabeça.

Em todos os navegadores que testei (Google Chrome, Firefox, Safari, Internet Explorer), ele funciona muito bem, exceto no IE. Tudo é injetado muito bem no IE pela primeira vez, mas depois disso ele nunca faz a ligação /game/getpuzzleinfo. É como se tivesse armazenado em cache os resultados ou algo assim.

Se eu mudar a chamada para o $.post("/game/getpuzzleinfo", ...IE, ela atende muito bem. Mas o Firefox deixa de funcionar.

Alguém pode esclarecer isso sobre o motivo pelo qual o IE está armazenando em cache minhas $.getchamadas ajax?

ATUALIZAR

De acordo com a sugestão abaixo, alterei minha solicitação de ajax para isso, que corrigiu meu problema:

$.ajax({
    type: "GET",
    url: "/game/getpuzzleinfo",
    dataType: "json",
    cache: false,
    success: function(data) { ... }
});
Micah
fonte
8
Obrigado por perguntar isso. Estou sem palavras que esse comportamento do navegador.
jjohn
1
Boa pergunta e site muito legal. Boa ideia.
MikeMurko

Respostas:

177

O IE é notório por seu cache agressivo das respostas do Ajax. Enquanto você usa o jQuery, você pode definir uma opção global:

$.ajaxSetup({
    cache: false
});

o que fará com que o jQuery adicione um valor aleatório à string de consulta de solicitação, impedindo o IE de armazenar em cache a resposta.

Observe que, se houver outras chamadas do Ajax onde você deseja armazenar em cache, isso também será desativado para elas. Nesse caso, mude para o método $ .ajax () e ative essa opção explicitamente para as solicitações necessárias.

Consulte http://docs.jquery.com/Ajax/jQuery.ajaxSetup para obter mais informações.

NickFitz
fonte
1
Você também pode adicionar um carimbo de data / hora ao final dos seus URLs. Não sei por que o jQuery não segue essa abordagem.
Eric Johnson
14
@ Eric: é isso que o jQuery faz internamente - a opção "cache: false" diz apenas para fazer isso.
NickFitz
Por que o jquery não tem isso por padrão?
speedplane 7/12/11
Acabei de perceber que as opções de cache não funcionam quando você tenta solicitar a página inicial no IE 8, com uma chamada para /. Altere para /index.phpou qualquer que seja o URL completo. Ou adicionar alguns parâmetros falsos-se como/?f=f
Hugo Delsing
8

Como marr75 mencionou, GETos são armazenados em cache.

Existem algumas maneiras de combater isso. Além de modificar o cabeçalho da resposta, você também pode anexar uma variável de cadeia de consulta gerada aleatoriamente ao final do URL de destino. Dessa forma, o IE pensará que é uma URL diferente cada vez que for solicitada.

Existem várias maneiras de fazer isso (como usar Math.random(), uma variação na data, etc.).

Aqui está uma maneira de fazer isso:

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

Gets são sempre armazenáveis ​​em cache. Uma estratégia que pode funcionar é editar o cabeçalho da resposta e dizer ao cliente para não armazenar em cache as informações ou expirar o cache muito em breve.

marr75
fonte
Parece uma boa ideia. Como eu faria isso?
Micah
1
Essa é uma pergunta carregada, depende do código do lado do servidor. Consulte a entrada da wikipedia "Lista de cabeçalhos HTTP" para obter um pouco de orientação. Exemplos: Controle de cache: sem cache Expira em: Qui, 01 de dezembro de 1994 16:00:00 GMT Basicamente, você precisa anexar esses cabeçalhos de resposta à sua resposta http. É bastante simples no ASP.NET, Ruby e PHP. Basta procurar o idioma do servidor que você está usando + modificar os cabeçalhos de resposta.
22755 marr75
3
Além disso, e isso não é uma crítica ao Jquery (eu amo essa biblioteca), o método de adicionar um parâmetro de sequência de consulta aleatória é seguro, mas indelicado para o cliente (pode deixá-los segurando itens no cache que nunca serão usados novamente).
22755 marr75
2

Se você estiver chamando a página ashx, também poderá desativar o cache no servidor com o seguinte código:

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

isto é o que eu faço para chamadas ajax:

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

funciona muito bem para mim.

Jason
fonte
1

O NickFitz fornece uma boa resposta, mas você também precisará desativar o cache no IE9. Para segmentar apenas o IE8 e o IE9, você pode fazer isso;

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

As respostas aqui são muito úteis para quem usa jQuery ou, por algum motivo, usa diretamente o objeto xmlHttpRequest ...

Se você estiver usando o proxy de serviço da Microsoft gerado automaticamente, não é tão simples de resolver.

O truque é usar o método Sys.Net.WebRequestManager.add_invokingRequest no manipulador de eventos, altere o URL da solicitação:

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

Eu publiquei um blog sobre isso: http://yoavniran.wordpress.com/2010/04/27/ie-caching-ajax-results-how-to-fix/

poeticGeek
fonte
0

Acabei de escrever um blog sobre esse problema exato usando apenas o ExtJS ( http://thecodeabode.blogspot.com/2010/10/cache-busting-ajax-requests-in-ie.html )

O problema era que, como eu estava usando um formato específico de reescrita de URL, não podia usar parâmetros convencionais de string de consulta (? Param = value), então escrevi o parâmetro de bloqueio de cache como uma variável postada ... que usar variáveis ​​POST é um pouco mais seguro que GET, simplesmente porque muitas estruturas MVC usam o padrão

protocolo: // host / controlador / ação / param1 / param2

e assim o mapeamento do nome da variável para o valor é perdido, e os parâmetros são simplesmente empilhados ... portanto, ao usar um parâmetro GET cache buster

ou seja, protocolo: // host / controlador / ação / param1 / param2 / no_cache122300201

no_cache122300201 pode ser confundido com um parâmetro $ param3 que pode ter um valor padrão

ie

ação de função pública ($ param1, $ param2, $ param3 = "valor padrão") {//..//}

nenhuma chance disso acontecer com os busters de cache POSTED

Ben
fonte
0

Se você estiver usando o ASP.NET MVC, basta adicionar esta linha na parte superior da ação do controlador:

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

}
batmaci
fonte
O comportamento em questão está no lado do navegador; Esta resposta está relacionada ao armazenamento em cache no servidor.
MarkSowul #
O @MarkSowul Outputcache possui 3 opções de Cliente, Servidor e qualquer. O IE usa o OutputCache como padrão, o que ocorre principalmente como cache do lado do cliente. Você pode ver mais detalhes aqui dougwilsonsa.wordpress.com/2011/04/29/...
batmaci
@ MarkSowul você também pode ver a pergunta relacionada e responder aqui. Você acha que isso também está do lado do servidor? stackoverflow.com/questions/2653092/...
batmaci
1
Sim, desculpe, você está certo - eu não perceber que sua resposta pode afetar tanto o cache do lado do servidor eo cache do lado do cliente.
MarkSowul #
-1

O IE está dentro de seus direitos para fazer esse cache; para garantir que o item não seja armazenado em cache, os cabeçalhos devem ser definidos de acordo.

Se você estiver usando o ASP.NET MVC, poderá escrever um ActionFilter; dentro OnResultExecuted, verifiquefilterContext.HttpContext.Request.IsAjaxRequest() . Nesse caso, defina o cabeçalho de vencimento da resposta:filterContext.HttpContext.Response.Expires = -1;

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

Algumas pessoas preferem usar o cabeçalho Cache-Control: no-cache em vez de expirar. Aqui está a diferença:
Cache-Control: no-cache - absolutamente NO caching
Expira: -1 - o navegador "normalmente" entra em contato com o servidor da Web para obter atualizações nessa página por meio de uma solicitação condicional If-Modified-Since. No entanto, a página permanece no cache do disco e é usada em situações apropriadas sem entrar em contato com o servidor da Web remoto, como quando os botões BACK e FORWARD são usados ​​para acessar o histórico de navegação ou quando o navegador está no modo offline.

Mark Sowul
fonte