Evitar el almacenamiento en caché del navegador del resultado de la llamada AJAX

262

Parece que si cargo contenido dinámico usando $.get(), el resultado se almacena en caché en el navegador.

Agregar una cadena aleatoria en QueryString parece resolver este problema (lo uso new Date().toString()), pero esto se siente como un truco.

¿Hay alguna otra forma de lograr esto? O, si la cadena única es la única forma de lograr esto, ¿alguna sugerencia que no sea new Date()?

Salamander2007
fuente
Puede usar la notación corta en $.now()lugar de hacer una (nueva Fecha (). GetTime ()) cada vez.
Dayson
1
El título de su pregunta es un poco engañoso. ¿Podría considerar cambiarle el nombre?
0112
44
¿Has considerado seleccionar otra respuesta como la aceptada?
M4N

Respuestas:

241

Yo uso new Date().getTime(), lo que evitará colisiones a menos que tenga varias solicitudes en el mismo milisegundo:

$.get('/getdata?_=' + new Date().getTime(), function(data) {
    console.log(data); 
});

Editar: Esta respuesta tiene varios años. Todavía funciona (por lo tanto, no lo he eliminado), pero hay formas mejores / más limpias de lograr esto ahora . Mi preferencia es para este método, pero esta respuesta también es útil si desea deshabilitar el almacenamiento en caché para cada solicitud durante la vida útil de una página.

Mark Bell
fuente
11
Voy a votar a favor solo porque es más limpio dejar que jQuery haga esto como en la respuesta de Peter J. Su solución funcionará, pero es más difícil de mantener a largo plazo.
Niklas Wulff
11
¿Qué parte de esto requiere mantenimiento? En comparación con lo que hace jQuery?
Sunny R Gupta
55
Puede valer la pena señalar que el new Date().getTime()código se utiliza como esto ... var nocache = new Date().getTime(); var path = 'http://hostname.domain.tld/api/somejsonapi/?cache=' + nocache;. Me tomó unos minutos resolver eso, yo mismo. Por supuesto, ?cachepodría ser cualquier redacción que la API no quiera realmente.
doubleJ
1
+1 incluso la respuesta de Peter J teniendo un mejor enfoque, esta respuesta no está mal ni es una mala respuesta. Creo que el DV está hecho porque el tuyo está por encima del de Peter (según lo aceptado). y el OP no aparece en SO desde principios de 2013
Michel Ayres
1
url = url + (-1 === url.indexOf('?') ? '?' : '&') + "__=" + Number(new Date());
514

Lo siguiente evitará que todas las futuras solicitudes AJAX se almacenen en caché, independientemente del método jQuery que utilice ($ .get, $ .ajax, etc.)

$.ajaxSetup({ cache: false });
Peter J
fuente
77
Tras la investigación (Fiddler), parece que jQuery implementa esto internamente simplemente agregando una marca de tiempo de todos modos (como se discutió en otras partes de estas respuestas). Para mí, el método .ajaxSetup es más limpio (en mi opinión)
Peter J
8
De hecho, no necesita estar dentro de la llamada de documento listo.
Peter J
19
¿Por qué deshabilitar el almacenamiento en caché ajax a nivel mundial? Creo que debería hacerse por llamada, como lo que hace la respuesta de Jonathan.
Sunny R Gupta
55
Lo que sea que funcione para tu aplicación. Continúo usando este método en aplicaciones comerciales siempre que necesito datos nuevos para todas las llamadas AJAX. Para otros, los datos en caché están bien.
Peter J
1
Descripción del enlace : establezca valores predeterminados para futuras solicitudes de Ajax. No se recomienda su uso.
itwebdeveloper
319

$ .Get () de JQuery almacenará en caché los resultados. En vez de

$.get("myurl", myCallback)

debe usar $ .ajax, que le permitirá desactivar el almacenamiento en caché:

$.ajax({url: "myurl", success: myCallback, cache: false});
Jonathan Moffatt
fuente
62
+1 Esta es la respuesta correcta. La solución de Peter J de deshabilitar el almacenamiento en caché a nivel mundial es una mala práctica de la OMI.
Salman von Abbas
77
Es importante tener en cuenta que solo es "global" para la página / solicitud.
Peter J
3
+1: el almacenamiento en caché debe ser específico para el tipo de solicitud. Es posible que algunas solicitudes del servidor necesiten el almacenamiento en caché (donde los datos del servidor son estáticos), por lo que es mejor elegir el almacenamiento en caché a pedido por solicitud que simplemente desactivarlo .
Gone Coding
1
+1 para la respuesta correcta: evitar el almacenamiento en caché por llamada utilizando el método de jQuery, en lugar de un hack manual.
Brendan Hill
2
Otra buena respuesta. Tengo que decir que, para mí, la mayor parte del tiempo deshabilitar globalmente el caché ha sido de gran beneficio. Sin embargo, todo depende de cómo esté diseñada su aplicación. No hay una viñeta plateada, pero en esta situación, recomendaría una función que acepte un valor booleano para el almacenamiento en caché, una función para devolución de llamada y una URL para modularidad. El "hack" manual está bien, pero si está utilizando jQuery, cumpla con sus funciones siempre que sea posible. Esto no solo facilitará el desarrollo ahora, sino también las futuras actualizaciones de la biblioteca.
Anthony Mason
24

Todas las respuestas aquí dejan una huella en la URL solicitada que se mostrará en los registros de acceso del servidor.

Necesitaba una solución basada en encabezado sin efectos secundarios y descubrí que se puede lograr configurando los encabezados mencionados en Cómo controlar el almacenamiento en caché de la página web en todos los navegadores. .

El resultado, al menos para Chrome, sería:

$.ajax({
   url: url, 
   headers: {
     'Cache-Control': 'no-cache, no-store, must-revalidate', 
     'Pragma': 'no-cache', 
     'Expires': '0'
   }
});

Ayuda en
fuente
Tal vez una pregunta estúpida, pero si mi ajax devuelve imágenes, ¿las imágenes se almacenarán en caché? Para evitar solicitudes masivas de Amazon S3?
Marcelo Agimóvel
Marcelo Agimóvel, esa puede ser una pregunta SO separada, creo.
Aidin
23

otra forma es no proporcionar encabezados de caché desde el lado del servidor en el código que genera la respuesta a la llamada ajax:

response.setHeader( "Pragma", "no-cache" );
response.setHeader( "Cache-Control", "no-cache" );
response.setDateHeader( "Expires", 0 );
miceuz
fuente
17
Incorrecto. En IE, los encabezados sin caché se ignoran para las llamadas XMLHttpRequest, como se explica aquí: stackoverflow.com/questions/244918/… Las DateTime (o mi método .ajaxSetup) son las únicas soluciones que realmente funcionan.
Peter J
Acabo de pegar mi habitual sin caché mantra, no es afirmó que de IE específica
miceuz
2
Esto debería apagar el almacenamiento en caché para todos los navegadores: response.setHeader ("Cache-Control", "max-age = 0, no-cache, no-store, post-check = 0, pre-check = 0");
Chris Broski
13

Personalmente, creo que el método de cadena de consulta es más confiable que intentar configurar encabezados en el servidor; no hay garantía de que un proxy o navegador no lo almacene en caché de todos modos (algunos navegadores son peores que otros, sin nombrar nombres).

Usualmente uso, Math.random()pero no veo nada de malo en usar la fecha (no deberías estar haciendo solicitudes AJAX lo suficientemente rápido como para obtener el mismo valor dos veces).

Greg
fuente
2
Combine Date (). GetTime () junto con Math.random () y debería estar en el lado seguro. En una nota al margen, Ext.Ajax también usa getTime () cuando se especifica disableCaching.
vividos
12

Siguiendo la documentación: http://api.jquery.com/jquery.ajax/

puede usar la cachepropiedad con:

$.ajax({
    method: "GET",
    url: "/Home/AddProduct?",
    data: { param1: value1, param2: value2},
    cache: false,
    success: function (result) {
        // TODO
    }
});
MrMins
fuente
5

Por supuesto, las técnicas de "ruptura de caché" harán el trabajo, pero esto no sucedería en primer lugar si el servidor le indica al cliente que la respuesta no debe almacenarse en caché. En algunos casos, es beneficioso almacenar respuestas en caché, algunas veces no. Deje que el servidor decida la vida útil correcta de los datos. Es posible que desee cambiarlo más tarde. Mucho más fácil de hacer desde el servidor que desde muchos lugares diferentes en su código de UI.

Por supuesto, esto no ayuda si no tienes control sobre el servidor.

Mark Renouf
fuente
5

¿Qué pasa con el uso de una solicitud POST en lugar de un GET ...? (Que deberías de todos modos ...)

Thomas Hansen
fuente
Creo que es una mejor solución, pero lamentablemente yo (de alguna manera) solo puedo hacer una solicitud GET. Entonces ... es nuevo Date (). GetTime () por ahora.
Salamander2007
Agregue alguna explicación a su respuesta para que otros puedan aprender de ella. ¿Por qué debería ser necesaria una solicitud POST?
Nico Haase
5

La verdadera pregunta es por qué necesita que esto no se almacene en caché. Si no debe almacenarse en caché porque cambia todo el tiempo, el servidor debe especificar no almacenar en caché el recurso. Si solo cambia a veces (porque uno de los recursos de los que depende puede cambiar), y si el código del cliente tiene una forma de saberlo, puede agregar un parámetro ficticio a la URL que se calcula a partir de algún hash o última fecha de modificación de esos recursos (eso es lo que hacemos en los recursos de secuencia de comandos de Microsoft Ajax para que se puedan almacenar en caché para siempre, pero las nuevas versiones aún se pueden servir a medida que aparecen). Si el cliente no puede conocer los cambios, la forma correcta debería ser que el servidor maneje las solicitudes HEAD correctamente y le diga al cliente si debe usar la versión en caché o no. Me parece que agregar un parámetro aleatorio o decirle al cliente que nunca almacene en caché es incorrecto porque la capacidad de almacenamiento en caché es una propiedad del recurso del servidor, por lo que debe decidirse del lado del servidor. Otra pregunta que debe hacerse es si este recurso realmente debería ser servido a través de GET o debería pasar por POST. Esa es una cuestión de semántica, pero también tiene implicaciones de seguridad (hay ataques que funcionan solo si el servidor permite GET). POST no se almacenará en caché.


fuente
66
¿Qué sucede si está pasando por servidores proxy que no controla su política de almacenamiento en caché? ¿Qué pasa si su aplicación necesita explícitamente hacer una nueva solicitud cada vez? La respuesta a las cosas no siempre es clara en blanco y negro, siempre hay áreas grises.
7wp
Es cierto que no siempre es claro. Pero ver esta respuesta me hizo cuestionar mis suposiciones y me llevó a encontrar la causa raíz de mi problema. Puede que ese no sea el caso para todos, pero me ayudó. Si estás leyendo esto, deberías considerarlo también.
Jonathan Tran
Esto me ayudó, ResponseCaching se configuró en el servidor de 60m por defecto. Lo cambió a No-Cache y dejó de almacenar en caché al cliente.
Mattygee
4

Tal vez debería mirar $ .ajax () en su lugar (si está usando jQuery, que parece). Eche un vistazo a: http://docs.jquery.com/Ajax/jQuery.ajax#options y la opción "caché".

Otro enfoque sería observar cómo almacena en caché las cosas en el lado del servidor.

finpingvin
fuente
1
Desafortunadamente, después de alguna investigación, usar $ .ajax () y establecer cache = false básicamente hará lo mismo. jQuery agregará algún número aleatorio a la cadena de consulta, y no verificará la cadena de consulta existente. Entonces supongo que usar $ .get () será suficiente.
Salamander2007
Ah bueno. Nunca lo intenté, solo recordé que había visto algo al respecto en los documentos :)
finpingvin
Ni siquiera es necesario usar $ .ajax. Simplemente use .ajaxSetup.
Peter J
3

Una pequeña adición a las excelentes respuestas dadas: si está ejecutando una solución de copia de seguridad que no sea ajax para usuarios sin javascript, de todos modos tendrá que obtener esos encabezados del lado del servidor correctos. Esto no es imposible, aunque entiendo a aquellos que lo abandonan;)

Estoy seguro de que hay otra pregunta sobre SO que le dará el conjunto completo de encabezados que son apropiados. No estoy completamente convencido de que la respuesta de los ratones cubra todas las bases al 100%.

krosenvold
fuente
3

Para aquellos de ustedes que usan la cacheopción de $.ajaxSetup()Safari móvil, parece que puede que tenga que usar una marca de tiempo para POST, ya que Safari móvil también lo almacena en caché. De acuerdo con la documentación sobre $.ajax()(a la que se le dirige $.ajaxSetup()):

Establecer caché en falso solo funcionará correctamente con las solicitudes HEAD y GET. Funciona agregando "_ = {marca de tiempo}" a los parámetros GET. El parámetro no es necesario para otros tipos de solicitudes, excepto en IE8 cuando se realiza una POST a una URL que ya ha sido solicitada por un GET.

Por lo tanto, configurar esa opción solo no lo ayudará en el caso que mencioné anteriormente.

Athasach
fuente
2

Básicamente, solo agregue cache:false;el ajax donde cree que el contenido cambiará a medida que avance el progreso. Y el lugar donde el contenido no cambiará allí puede omitir esto. De esta manera obtendrás la nueva respuesta cada vez

Santosh Upadhayay
fuente
2

Ahora, es fácil hacerlo habilitando / deshabilitando la opción de caché en su solicitud ajax, así

$(function () {
    var url = 'your url goes here';
    $('#ajaxButton').click(function (e) {
        $.ajax({
            url: url,
            data: {
                test: 'value'
            },
                cache: true, //cache enabled, false to reverse
                complete: doSomething
            });
        });
    });
    //ToDo after ajax call finishes
    function doSomething(data) {
        console.log(data);
    }
});
Omar El Don
fuente
3
Después de 6 años, ¿estás dando la misma respuesta que Jonathan? ಠ_ಠ
redent84
la gente puede decir que son 6 años después de que se publique la pregunta. Y mi respuesta a esa pregunta es diferente a cualquier otra, sin mencionar que es la correcta hoy en día. ¡Responder tales preguntas no es para el "autor de la pregunta", es para la comunidad y los principiantes! ¡Gracias por agregar la aclaración de todos modos!
Omar El Don
¿Y cuál es la diferencia entre el tuyo y este stackoverflow.com/a/735084/469218 ?
redent84
¡Quizás sea claridad, desde el punto de vista de un principiante que hace una pregunta así!
Omar El Don
1

Como dijo @Athasach, según los documentos de jQuery, $.ajaxSetup({cache:false}) no funcionará para otras solicitudes que no sean GET y HEAD.

Es mejor enviar de vuelta un Cache-Control: no-cache encabezado desde su servidor de todos modos. Proporciona una separación más limpia de las preocupaciones.

Por supuesto, esto no funcionaría para las URL de servicio que no pertenecen a su proyecto. En ese caso, puede considerar enviar el servicio de terceros desde el código del servidor en lugar de llamarlo desde el código del cliente.

rstackhouse
fuente
1

Si está utilizando .net ASP MVC, deshabilite el almacenamiento en caché en la acción del controlador agregando el siguiente atributo en la función de punto final:

[OutputCacheAttribute(VaryByParam = "*", Duration = 0, NoStore = true)]
Mario
fuente
¿Puedes explicar eso más? ¿Cómo se relaciona esa matriz con AJAX?
Nico Haase
No es una matriz, es un atributo en una acción de controlador MVC.
Marius
0

agregar encabezado

headers: {
                'Cache-Control':'no-cache'
            }
Moaz Salem
fuente
Agregue alguna explicación a su respuesta para que otros puedan aprender de ella: ¿ dónde deben agregarse esos encabezados?
Nico Haase
-3

anexar Math.random() a la url de solicitud

xiaoyifang
fuente
2
Esto dará resultados inestables.
aj.toulan
Math.random solo actuará como un parámetro, como url? _ = [Math.Random ()], no tiene nada que ver con un resultado inestable.
xiaoyifang
44
Entiendo lo que estabas haciendo. Simplemente estaba comentando que Math.Random () a veces te dará el mismo número dos veces. Si llena su sistema con incertidumbres, solo se agregarán una encima de la otra.
aj.toulan