Problema di memorizzazione nella cache IE angolare per $ http


251

Tutte le chiamate ajax che vengono inviate da IE vengono memorizzate nella cache da Angular e ottengo una a 304 responseper tutte le chiamate successive. Sebbene la richiesta sia la stessa, la risposta non sarà la stessa nel mio caso. Voglio disabilitare questa cache. Ho provato ad aggiungere il cache attribute$ http.get ma ancora non ha aiutato. Come si può risolvere questo problema?

Risposte:


439

Invece di disabilitare la memorizzazione nella cache per ogni singola richiesta GET, la disabilito globalmente nel $ 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';
}]);

78
L' If-Modified-Sinceintestazione fa sì che IIS + iisnode generi 400 richieste non valide per ogni file html caricato attraverso ngIncludee ngView. I seguenti due header hanno risolto il problema per me (li ho estratti da Chrome, che non aveva il problema di memorizzazione nella cache): $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache'; $httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
Langdon

4
A mio avviso questa risposta dovrebbe essere contrassegnata come la risposta, mentre la soluzione fornita da Martin funziona, è più un trucco che una soluzione reale.
Robba,

4
Questo ha funzionato per le mie richieste GET locali, ma ha causato l'avvio di una richiesta CORS che stavo facendo utilizzando il metodo OPTIONS anziché il metodo GET. Il server di terze parti non supporta il metodo OPTIONS, quindi la mia soluzione alternativa è utilizzare jQuery.get () per effettuare quella richiesta e utilizzare $ scope.apply () nei gestori di risposta.
Ben

13
L'utilizzo If-Modified-Since = "0"dell'intestazione interrompe Tomcat (problema con l'analisi della data dell'intestazione, poiché 0non è un valore valido RFC ). Risolto utilizzando Mon, 26 Jul 1997 05:00:00 GMTinvece il valore .
Lopisan,

6
Non ho usato l'intestazione "If-Modified-Since" e ha funzionato senza. Sono necessari solo gli altri due.
Michael Mahony,

69

Puoi aggiungere una querystring unica (credo che questo sia ciò che jQuery fa con la cache: opzione falsa) alla richiesta.

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

Una soluzione forse migliore è se si ha accesso al server, quindi è possibile assicurarsi che le intestazioni necessarie siano impostate per impedire la memorizzazione nella cache. Se stai usando ASP.NET MVC questa risposta potrebbe essere d'aiuto.


2
$http.get(url+ "?"+new Date().toString())è solo un'altra rappresentazione, senza utilizzare il parametro ma aggiungendolo alla stringa di query.
Davut Gürbüz,

28

puoi aggiungere un intercettore.

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

è necessario rimuovere le righe console.log dopo aver verificato.


E dovresti usare $lognel caso in cui ti dimentichi di eliminarli.
Carl G,

2
Sto riscontrando seri problemi di memorizzazione nella cache in Internet Explorer, che porta a una pagina vuota, perché parti importanti non sono state eseguite. L'uso dell'intercettore puntato ha risolto questo problema! +1
raoulinski,

Penso che questo sia l'approccio migliore, poiché evita problemi con il comportamento di CORS e IE nell'innescare una richiesta di verifica preliminare se aggiungi intestazioni aggiuntive. Questo sembra essere il metodo più sicuro per non incorrere in ulteriori problemi
Chrismarx,

@dilip pattnaik: - Perché questo problema si verifica con angolare e cioè?
MiHawk,

14

Ho semplicemente aggiunto tre meta tag in index.html sul progetto angolare e il problema della cache è stato risolto su 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">

2
Avevamo già quei meta tag nei nostri index.htmlquando abbiamo notato che IE11 stava memorizzando nella cache le richieste AJAX: / ​​Ma la configurazione $httpProvidercome mostrato in altre risposte ha funzionato bene.
walen

14

Duplicazione della mia risposta in un'altra discussione .

Per Angular 2 e versioni successive , il modo più semplice per aggiungere no-cacheintestazioni sostituendo 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'
    });
}

E fai riferimento nel tuo modulo:

@NgModule({
    ...
    providers: [
        ...
        { provide: RequestOptions, useClass: CustomRequestOptions }
    ]
})

Quelli non sarebbero intestazioni per la risposta del server, non per la richiesta del browser? (Immagino che uno potrebbe impostare If-Modified-Sincecon qualche data lontana in passato usando il metodo sopra.)
Arjan

@Vitaliy: - Perché questo problema si verifica con angolare e cioè?
MiHawk,

Il tuo approccio rimuoverà tutte le intestazioni personalizzate che sono già lì. Quindi, procedi come segue invece di creare un nuovo oggetto Header. 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

Quello garantito di cui avevo lavorato era qualcosa del genere:

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

Ho dovuto fondersi 2 delle soluzioni di cui sopra, al fine di garantire il corretto utilizzo di tutti i metodi, ma è possibile sostituire commoncon geto metodo diverso cioè put, post, deleteper fare questo lavoro per i casi diversi.


puoi dirmi dove nel codice hai aggiunto questo al file angular.js? quale riga #?
JonathanScialpi,

@JonathanScialpi L'ho aggiornato per mostrare dove avrei potuto inserirlo. Dove si trova all'interno della funzione anonima non dovrebbe importare.
Markyzm,

@marksyzm puoi dirmi qual è il significato di questa lineaif (!$httpProvider.defaults.headers.get) { $httpProvider.defaults.headers.common = {}; }
Monojit Sarkar

@MonojitSarkar Ah, che avrebbe dovuto essere headers.common nell'istruzione if, grazie per quel puntatore
markyzm

1
["If-Modified-Since"] = "0"è illegale e genera una richiesta non valida su alcuni back-end. dovrebbe essere una data.
jenson-button-event,

8

Questa unica riga mi ha aiutato (Angular 1.4.8):

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

UPD: Il problema è che IE11 esegue una memorizzazione nella cache aggressiva. Quando stavo esaminando Fiddler ho notato che in modalità F12 le richieste inviano "Pragma = no-cache" e l'endpoint viene richiesto ogni volta che visito una pagina. Ma in modalità normale l'endpoint è stato richiesto solo una volta alla prima volta in cui ho visitato la pagina.


1
Cordiali saluti, questa risposta ha causato un problema CORS durante la richiesta di file dall'archivio BLOB di Azure, difficile da rintracciare ma alla fine capito che questa era la causa. La rimozione dell'intestazione pragma ha risolto il mio problema CORS (ma ha ripristinato il problema di memorizzazione nella cache di IE).
keithl8041,

7

Per evitare la memorizzazione nella cache, un'opzione è fornire un URL diverso per la stessa risorsa o dati. Per generare un URL diverso, è possibile aggiungere una stringa di query casuale alla fine dell'URL. Questa tecnica funziona per richieste ajax di tipo JQuery, angolare o di altro tipo.

myURL = myURL +"?random="+new Date().getTime();

6

Ottengo risolto aggiungendo datetime come un numero casuale:

$http.get("/your_url?rnd="+new Date().getTime()).success(function(data, status, headers, config) {
    console.log('your get response is new!!!');
});

: - Perché questo problema si verifica con angolare e cioè?
MiHawk,

4

La soluzione sopra funzionerà (rendi unico l'URL aggiungendo nella querystring un nuovo parametro) ma preferisco la soluzione proposta [qui]: un modo migliore per prevenire la cache IE in AngularJS?, che gestiscono ciò a livello di server in quanto non è specifico di IE. Voglio dire, se quella risorsa non deve essere memorizzata nella cache, fallo sul server (questo non ha nulla a che fare con il browser utilizzato; è intrisico per la risorsa).

Ad esempio, in Java con JAX-RS, farlo programmaticamente per JAX-RS v1 o in modo declinante per JAX-RS v2.

Sono sicuro che qualcuno capirà come farlo


1
Sebbene possa essere elaborato, questo è il modo corretto di farlo. Il lato client non dovrebbe scegliere cosa memorizzare nella cache o meno, ma dovrebbe essere il server a dire al client cosa deve essere memorizzato nella cache o meno.
Archimede Trajano,

Sono pienamente d'accordo, questo deve essere un modo corretto
smnbbrv

1

Questo è un po 'vecchio ma: soluzioni come sono obsolete. Consentire al server di gestire la cache o meno (nella risposta). L'unico modo per garantire l'assenza di memorizzazione nella cache (pensando alle nuove versioni in produzione) è modificare il file js o css con un numero di versione. Lo faccio con il webpack.


1

inoltre puoi provare nel tuo servizio per impostare le intestazioni come ad esempio:

...
import {Injectable} da "@ angular / core";
importare {HttpClient, HttpHeaders, HttpParams} da "@ angular / common / http";
...
 @Injectable ()
classe di esportazione MyService {

    intestazioni private: HttpHeaders;


    costruttore (privato http: HttpClient ..) 
    {


        this.headers = new HttpHeaders ()
                    .append ("Content-Type", "application / json")
                    .append ("Accetta", "application / json")
                    .append ("LanguageCulture", this.headersLanguage)
                    .append ("Cache-Control", "no-cache")
                    .append ("Pragma", "no-cache")                   
    }
}
....


0

Questo problema è dovuto al problema di memorizzazione nella cache di IE, come hai detto, puoi testarlo in modalità di debug di IE premendo f12 (funzionerà bene in modalità di debug) .IE non prenderà i dati del server ogni volta che la pagina chiama, ci vuole i dati dalla cache. Per disabilitare ciò, procedi in uno dei seguenti modi:

  1. aggiungere quanto segue all'URL della richiesta del servizio http

// Prima (emesso uno)

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

// Dopo (funzionando bene)

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

  1. disabilitare la cache per l'intero modulo: -

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


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

Ho appena aggiunto questo a View e ha iniziato a funzionare su IE. Confermato per lavorare su Angular 2.


0

Un'opzione è quella di utilizzare il semplice approccio di aggiungere un timestamp ad ogni richiesta senza necessità di svuotare la cache.

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

-2

Prova questo, ha funzionato per me in un caso simile: -

$http.get("your api url", {
headers: {
    'If-Modified-Since': '0',
    "Pragma": "no-cache",
    "Expires": -1,
    "Cache-Control": "no-cache, no-store, must-revalidate"
 }
})
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.