Problema de almacenamiento en caché de IE angular por $ http

251

Angular almacena en caché todas las llamadas ajax que se envían desde el IE y obtengo un 304 responsepara todas las llamadas posteriores. Aunque la solicitud es la misma, la respuesta no será la misma en mi caso. Quiero deshabilitar este caché. Intenté agregar el cache attribute$ http.get pero aún así no ayudó. ¿Cómo se puede resolver este problema?

Rahul
fuente

Respuestas:

439

En lugar de deshabilitar el almacenamiento en caché para cada solicitud GET, lo deshabilito globalmente en $ httpProvider:

myModule.config(['$httpProvider', function($httpProvider) {
    //initialize get if not there
    if (!$httpProvider.defaults.headers.get) {
        $httpProvider.defaults.headers.get = {};    
    }    

    // Answer edited to include suggestions from comments
    // because previous version of code introduced browser-related errors

    //disable IE ajax request caching
    $httpProvider.defaults.headers.get['If-Modified-Since'] = 'Mon, 26 Jul 1997 05:00:00 GMT';
    // extra
    $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache';
    $httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
}]);
cnmuc
fuente
78
El If-Modified-Sinceencabezado hace que IIS + iisnode arroje 400 solicitudes incorrectas por cada archivo html cargado a través de ngIncludey ngView. Sin embargo, los siguientes dos encabezados solucionaron el problema (los saqué de Chrome, que no tenía el problema de almacenamiento en caché): $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache'; $httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
Langdon
44
En mi opinión, esta respuesta debe marcarse como la respuesta, aunque la solución proporcionada por Martin funciona, es más un truco que una solución real.
Robba
44
Esto funcionó para mis solicitudes GET locales, pero provocó que la única solicitud CORS que estaba haciendo comenzara a usar el método OPTIONS en lugar del método GET. El servidor de terceros no admite el método OPTIONS, por lo que mi solución es usar jQuery.get () para hacer esa solicitud y usar $ scope.apply () en los controladores de respuestas.
Ben
13
El uso del If-Modified-Since = "0"encabezado rompe Tomcat (problema con el análisis de la fecha del encabezado, ya 0que no es un valor válido RFC ). Solucionado el uso de valor en su Mon, 26 Jul 1997 05:00:00 GMTlugar.
lopisan
66
No utilicé el encabezado "If-Modified-Since" y funcionó sin eso. Solo los otros dos son necesarios.
Michael Mahony
69

Puede agregar una cadena de consulta única (creo que esto es lo que hace jQuery con el caché: opción falsa) a la solicitud.

$http({
    url: '...',
    params: { 'foobar': new Date().getTime() }
})

Una solución quizás mejor es si tiene acceso al servidor, entonces puede asegurarse de que los encabezados necesarios estén configurados para evitar el almacenamiento en caché. Si está utilizando ASP.NET MVC esta respuesta, podría ayudar.

Martín
fuente
2
$http.get(url+ "?"+new Date().toString())es solo otra representación, sin usar el parámetro pero agregándolo a la cadena de consulta.
Davut Gürbüz
28

Puede agregar un interceptor.

myModule.config(['$httpProvider', function($httpProvider) {
 $httpProvider.interceptors.push('noCacheInterceptor');
}]).factory('noCacheInterceptor', function () {
            return {
                request: function (config) {
                    console.log(config.method);
                    console.log(config.url);
                    if(config.method=='GET'){
                        var separator = config.url.indexOf('?') === -1 ? '?' : '&';
                        config.url = config.url+separator+'noCache=' + new Date().getTime();
                    }
                    console.log(config.method);
                    console.log(config.url);
                    return config;
               }
           };
    });

debe eliminar las líneas de console.log después de verificar.

dillip pattnaik
fuente
Y debe usarlo $logen caso de que se olvide de sacarlos.
Carl G
2
Tengo serios problemas de almacenamiento en caché en IE, lo que lleva a una página en blanco, porque partes importantes no se ejecutaron. ¡Usar el interceptor propinado resolvió este problema! +1
raoulinski
Creo que este es el mejor enfoque, ya que evita problemas con el comportamiento de CORS e IE de activar una solicitud de verificación previa si agrega encabezados adicionales. Este parece ser el método más seguro para no tener problemas adicionales
chrismarx
@dilip pattnaik: - ¿Por qué ocurre este problema con angular y ie?
MiHawk
14

Simplemente agregué tres metaetiquetas en index.html en el proyecto angular, y el problema de caché se resolvió en IE.

<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="Sat, 01 Dec 2001 00:00:00 GMT">
rtato
fuente
2
Ya teníamos esas metaetiquetas index.htmlcuando notamos que IE11 estaba almacenando en caché las solicitudes de AJAX: / ​​Pero la configuración $httpProvidercomo se muestra en otras respuestas funcionó bien.
walen
14

Duplicando mi respuesta en otro hilo .

Para Angular 2 y posteriores , la forma más fácil de agregar no-cacheencabezados anulando RequestOptions:

import { Injectable } from '@angular/core';
import { BaseRequestOptions, Headers } from '@angular/http';

@Injectable()
export class CustomRequestOptions extends BaseRequestOptions {
    headers = new Headers({
        'Cache-Control': 'no-cache',
        'Pragma': 'no-cache',
        'Expires': 'Sat, 01 Jan 2000 00:00:00 GMT'
    });
}

Y referencialo en tu módulo:

@NgModule({
    ...
    providers: [
        ...
        { provide: RequestOptions, useClass: CustomRequestOptions }
    ]
})
Vitaliy Ulantikov
fuente
¿No serían esos encabezados para la respuesta del servidor, no para la solicitud del navegador? (Me imagino que se podría establecer If-Modified-Sinceuna fecha en el pasado usando el método anterior.)
Arjan
@Vitaliy: - ¿Por qué este problema ocurre con angular y ie?
MiHawk
Su enfoque eliminará cualquier encabezado personalizado que ya esté allí. Por lo tanto, haga lo siguiente en lugar de crear un nuevo objeto Encabezado. headers: req.headers .set('Cache-Control', 'no-cache') .set('Pragma', 'no-cache') .set('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT')
Chamika Goonetilaka
9

El garantizado que tenía trabajando era algo así:

myModule.config(['$httpProvider', function($httpProvider) {
    if (!$httpProvider.defaults.headers.common) {
        $httpProvider.defaults.headers.common = {};
    }
    $httpProvider.defaults.headers.common["Cache-Control"] = "no-cache";
    $httpProvider.defaults.headers.common.Pragma = "no-cache";
    $httpProvider.defaults.headers.common["If-Modified-Since"] = "Mon, 26 Jul 1997 05:00:00 GMT";
}]);

Tuve que fusionar 2 de las soluciones anteriores para garantizar el uso correcto de todos los métodos, pero puede reemplazarlo commoncon getotro método put, es decir post, deletepara que esto funcione en diferentes casos.

marksyzm
fuente
¿me puede decir en qué parte del código ha agregado esto al archivo angular.js? que linea #?
JonathanScialpi
@ JonathanScialpi Lo actualicé para mostrar dónde podría ponerlo. Dónde está dentro de la función anónima no debería importar.
marksyzm
@marksyzm ¿puedes decirme cuál es el significado de esta línea?if (!$httpProvider.defaults.headers.get) { $httpProvider.defaults.headers.common = {}; }
Monojit Sarkar
@MonojitSarkar Ah, se suponía que eran headers.common en la declaración if, gracias por ese puntero
marksyzm
1
["If-Modified-Since"] = "0"es ilegal y genera una solicitud incorrecta en algunos servidores. Debería ser una cita.
jenson-button-event
8

Esta única línea me ayudó (Angular 1.4.8):

$httpProvider.defaults.headers.common['Pragma'] = 'no-cache';

UPD: El problema es que IE11 hace un almacenamiento en caché agresivo. Cuando estaba buscando en Fiddler, noté que en el modo F12 las solicitudes envían "Pragma = no-cache" y se solicita un punto final cada vez que visito una página. Pero en modo normal, el punto final se solicitó solo una vez la primera vez que visité la página.

yamaxim
fuente
1
Solo para su información, esta respuesta causó un problema de CORS al solicitar archivos del almacenamiento de blobs de Azure, difícil de rastrear, pero finalmente descubrió que esta era la causa. La eliminación del encabezado pragma solucionó mi problema de CORS (pero reinstalé el problema de almacenamiento en caché de IE).
keithl8041
7

Para evitar el almacenamiento en caché, una opción es proporcionar una URL diferente para el mismo recurso o datos. Para generar una URL diferente, puede agregar una cadena de consulta aleatoria al final de la URL. Esta técnica funciona para JQuery, Angular u otro tipo de solicitudes ajax.

myURL = myURL +"?random="+new Date().getTime();
Razan Paul
fuente
6

Lo resuelvo agregando datetime como un número aleatorio:

$http.get("/your_url?rnd="+new Date().getTime()).success(function(data, status, headers, config) {
    console.log('your get response is new!!!');
});
khichar.anil
fuente
: - ¿Por qué ocurre este problema con angular y es decir?
MiHawk
4

La solución anterior funcionará (haga que la url sea única agregando en la cadena de consulta un nuevo parámetro), pero prefiero que la solución proponga [aquí]: ¿ Mejor manera de prevenir el caché de IE en AngularJS? , que manejan esto a nivel de servidor, ya que no es específico de IE. Quiero decir, si ese recurso no debe almacenarse en caché, hágalo en el servidor (esto no tiene nada que ver con el navegador utilizado; es intrínseco al recurso).

Por ejemplo, en java con JAX-RS, hágalo programáticamente para JAX-RS v1 o declarativamente para JAX-RS v2.

Estoy seguro de que alguien descubrirá cómo hacerlo

rguitter
fuente
1
Aunque se puede elaborar, esta es la forma correcta de hacerlo. El lado del cliente no debe elegir qué almacenar en caché o no, pero debe ser el servidor quien debe decirle al cliente qué debe almacenarse en caché o no.
Arquímedes Trajano
Estoy totalmente de acuerdo, esto debe ser una forma adecuada
smnbbrv
1

Esto es un poco viejo pero: las soluciones como son obsoletas. Deje que el servidor maneje el caché o no el caché (en la respuesta). La única forma de garantizar que no haya almacenamiento en caché (pensando en nuevas versiones en producción) es cambiar el archivo js o css con un número de versión. Hago esto con webpack.

Jens Alenius
fuente
1

También puede intentar en su servicio configurar encabezados como, por ejemplo:

...
importar {Inyectable} desde "@ angular / core";
importar {HttpClient, HttpHeaders, HttpParams} desde "@ angular / common / http";
...
 @Inyectable ()
clase de exportación MyService {

    encabezados privados: HttpHeaders;


    constructor (http privado: HttpClient ..) 
    {


        this.headers = new HttpHeaders ()
                    .append ("Content-Type", "application / json")
                    .append ("Aceptar", "aplicación / json")
                    .append ("LanguageCulture", this.headersLanguage)
                    .append ("Cache-Control", "no-cache")
                    .append ("Pragma", "sin caché")                   
    }
}
....
Sin nombre
fuente
0

Este problema se debe al problema de almacenamiento en caché de IE, como dijiste, puedes probarlo en modo de depuración de IE presionando f12 (esto funcionará bien en modo de depuración) .IE no tomará los datos del servidor cada vez que llame la página. Los datos del caché. Para deshabilitar esto, realice una de las siguientes acciones:

  1. agregue lo siguiente con su URL de solicitud de servicio http

// Antes (emitió uno)

this.httpService.get (this.serviceUrl + "/eAMobileService.svc/ValidateEngagmentName/" + engagementName, {})

// Después (trabajando bien)

this.httpService.get (this.serviceUrl + "/eAMobileService.svc/ValidateEngagmentName/" + engagementName + "? DateTime =" + new Date (). getTime () + '', {cache: false})

  1. deshabilitar el caché para todo el Módulo: -

$ httpProvider.defaults.headers.common ['Pragma'] = 'no-cache';

Nijas_kp
fuente
0
meta http-equiv="Cache-Control" content="no-cache"

Acabo de agregar esto a View y comenzó a funcionar en IE. Confirmado para trabajar en Angular 2.

Cerveza de jengibre
fuente
0

Una opción es utilizar el enfoque simple de agregar una marca de tiempo con cada solicitud sin necesidad de borrar el caché.

    let c=new Date().getTime();
    $http.get('url?d='+c)
Vaimeo
fuente
-2

Prueba esto, funcionó para mí en un caso similar:

$http.get("your api url", {
headers: {
    'If-Modified-Since': '0',
    "Pragma": "no-cache",
    "Expires": -1,
    "Cache-Control": "no-cache, no-store, must-revalidate"
 }
})
Mayank Parnami
fuente