Angular IE Caching-Problem für $ http

251

Alle Ajax-Anrufe, die vom IE gesendet werden, werden von Angular zwischengespeichert, und ich erhalte eine 304 responsefür alle nachfolgenden Anrufe. Obwohl die Anfrage dieselbe ist, wird die Antwort in meinem Fall nicht dieselbe sein. Ich möchte diesen Cache deaktivieren. Ich habe versucht, das cache attributezu $ http.get hinzuzufügen, aber es hat trotzdem nicht geholfen. Wie kann dieses Problem behoben werden?

Rahul
quelle

Antworten:

439

Anstatt das Caching für jede einzelne GET-Anfrage zu deaktivieren, deaktiviere ich es global im $ 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
quelle
78
Der If-Modified-SinceHeader lässt IIS + iisnode 400 Bad Request für jede durch ngIncludeund geladene HTML-Datei auslösen ngView. Die folgenden zwei Header haben das Problem für mich behoben (ich habe sie aus Chrome gezogen, wo es kein Caching-Problem gab): $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache'; $httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
Langdon
4
Meiner Meinung nach sollte diese Antwort als Antwort markiert werden, während die von Martin bereitgestellte Lösung funktioniert, ist sie eher ein Hack als eine tatsächliche Lösung.
Robba
4
Dies funktionierte für meine lokalen GET-Anforderungen, führte jedoch dazu, dass die eine CORS-Anforderung, die ich stellte, die OPTIONS-Methode anstelle der GET-Methode verwendete. Der Server eines Drittanbieters unterstützt die OPTIONS-Methode nicht. Daher besteht meine Problemumgehung darin, jQuery.get () zu verwenden, um diese Anforderung zu stellen, und $ scope.apply () in den Antworthandlern zu verwenden.
Ben
13
Die Verwendung des If-Modified-Since = "0"Headers unterbricht Tomcat (Problem beim Parsen des Headerdatums, da der 0Wert RFC nicht gültig ist ). Mon, 26 Jul 1997 05:00:00 GMTStattdessen mit Wert behoben.
Lopisan
6
Ich habe den Header "If-Modified-Since" nicht verwendet und es hat ohne das funktioniert. Nur die anderen beiden sind notwendig.
Michael Mahony
69

Sie können der Anforderung entweder einen eindeutigen Querystring anhängen (ich glaube, das macht jQuery mit der Option cache: false).

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

Eine vielleicht bessere Lösung ist, wenn Sie Zugriff auf den Server haben, können Sie sicherstellen, dass die erforderlichen Header festgelegt sind, um das Caching zu verhindern. Wenn Sie ASP.NET MVC diese Antwort verwenden, kann dies hilfreich sein.

Martin
quelle
2
$http.get(url+ "?"+new Date().toString())ist nur eine andere Darstellung, ohne Parameter zu verwenden, sondern sie der Abfragezeichenfolge hinzuzufügen.
Davut Gürbüz
28

Sie können einen Abfangjäger hinzufügen.

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

Sie sollten die Zeilen console.log nach der Überprüfung entfernen.

Dillip Pattnaik
quelle
Und Sie sollten verwenden, $logfalls Sie vergessen, sie herauszunehmen.
Carl G
2
Ich habe ernsthafte Caching-Probleme im IE, die zu einer leeren Seite führen, da wichtige Teile nicht ausgeführt wurden. Die Verwendung des vorgeschlagenen Abfangjägers löste dieses Problem! +1
raoulinski
Ich denke, dies ist der beste Ansatz, da dadurch Probleme mit dem Verhalten von CORS und IE beim Auslösen einer Preflight-Anforderung vermieden werden, wenn Sie zusätzliche Header hinzufügen. Dies scheint die sicherste Methode zu sein, um nicht auf zusätzliche Probleme zu
stoßen
@dilip pattnaik: - Warum tritt dieses Problem bei eckigen und dh?
MiHawk
14

Ich habe einfach drei Meta-Tags in index.html für ein Winkelprojekt hinzugefügt, und das Cache-Problem wurde im IE behoben.

<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
quelle
2
Wir hatten diese Meta-Tags bereits in unserem, index.htmlals wir bemerkten, dass IE11 AJAX-Anfragen zwischenspeichert: / Aber die Konfiguration $httpProviderwie in anderen Antworten gezeigt funktionierte einwandfrei .
Wal
14

Dupliziere meine Antwort in einem anderen Thread .

Für Angular 2 und höher ist der einfachste Weg, no-cacheHeader durch Überschreiben hinzuzufügen 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'
    });
}

Und verweisen Sie in Ihrem Modul darauf:

@NgModule({
    ...
    providers: [
        ...
        { provide: RequestOptions, useClass: CustomRequestOptions }
    ]
})
Vitaliy Ulantikov
quelle
Wären das nicht Header für die Serverantwort, nicht für die Browseranforderung? (Ich könnte mir vorstellen, dass man If-Modified-Sincemit der obigen Methode ein Datum weit in der Vergangenheit einstellen könnte .)
Arjan
@Vitaliy: - Warum tritt dieses Problem bei eckigen und dh?
MiHawk
Ihr Ansatz entfernt alle benutzerdefinierten Header, die bereits vorhanden sind. Führen Sie daher die folgenden Schritte aus, anstatt ein neues Header-Objekt zu erstellen. 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

Die garantierte Arbeit, die ich hatte, war etwas in dieser Richtung:

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

Ich hatte zwei der oben genannten Lösungen zusammenführen , um die korrekte Verwendung für alle Methoden zu gewährleisten, aber Sie können ersetzen commonmit getoder einem anderen Verfahren , dh put, post, deletediese Arbeit für verschiedene Fälle zu machen.

marksyzm
quelle
Können Sie mir sagen, wo Sie dies im Code zur Datei angle.js hinzugefügt haben? welche Zeile #?
JonathanScialpi
@ JonathanScialpi Ich habe es aktualisiert, um zu zeigen, wo ich es platzieren könnte. Wo es sich innerhalb der anonymen Funktion befindet, sollte keine Rolle spielen.
Marksyzm
@marksyzm können Sie mir bitte sagen, was die Bedeutung dieser Zeile istif (!$httpProvider.defaults.headers.get) { $httpProvider.defaults.headers.common = {}; }
Monojit Sarkar
@ MonojitSarkar Ah, das sollte headers.common in der if-Anweisung sein, danke für diesen Zeiger
marksyzm
1
["If-Modified-Since"] = "0"ist illegal und generiert an einigen Backends eine Bad Request. Es sollte ein Datum sein.
Jenson-Button-Event
8

Diese einzige Zeile hat mir geholfen (Angular 1.4.8):

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

UPD: Das Problem ist, dass IE11 aggressives Caching ausführt. Als ich mich mit Fiddler befasste, bemerkte ich, dass im F12-Modus Anfragen "Pragma = kein Cache" senden und bei jedem Besuch einer Seite ein Endpunkt angefordert wird. Im normalen Modus wurde der Endpunkt jedoch beim ersten Besuch der Seite nur einmal angefordert.

Yamaxim
quelle
1
Nur zu Ihrer Information, diese Antwort verursachte ein CORS-Problem beim Anfordern von Dateien aus dem Azure-Blob-Speicher, das schwer zu finden war, aber schließlich herausfand, dass dies die Ursache war. Durch das Entfernen des Pragma-Headers wurde mein CORS-Problem behoben (das IE-Caching-Problem wurde jedoch erneut installiert).
keithl8041
7

Um ein Caching zu vermeiden, besteht eine Option darin, unterschiedliche URLs für dieselbe Ressource oder dieselben Daten anzugeben. Um eine andere URL zu generieren, können Sie am Ende der URL eine zufällige Abfragezeichenfolge hinzufügen. Diese Technik funktioniert für JQuery-, Angular- oder andere Ajax-Anforderungen.

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

Ich habe es gelöst, indem ich datetime als Zufallszahl angehängt habe:

$http.get("/your_url?rnd="+new Date().getTime()).success(function(data, status, headers, config) {
    console.log('your get response is new!!!');
});
khichar.anil
quelle
: - Warum tritt dieses Problem bei eckigen und dh auf?
MiHawk
4

Die obige Lösung funktioniert (machen Sie die URL eindeutig, indem Sie im Querystring einen neuen Parameter hinzufügen), aber ich bevorzuge den Lösungsvorschlag [hier]: Besserer Weg, um den IE-Cache in AngularJS zu verhindern? , die dies auf Serverebene behandeln, da es nicht spezifisch für IE ist. Ich meine, wenn diese Ressource nicht zwischengespeichert werden soll, tun Sie dies auf dem Server (dies hat nichts mit dem verwendeten Browser zu tun; es ist für die Ressource von zentraler Bedeutung).

Zum Beispiel in Java mit JAX-RS programmgesteuert für JAX-RS v1 oder deklarativ für JAX-RS v2.

Ich bin sicher, jeder wird herausfinden, wie es geht

rguitter
quelle
1
Obwohl es ausgearbeitet werden kann, ist dies der richtige Weg, dies zu tun. Die Clientseite sollte nicht auswählen, was zwischengespeichert werden soll oder nicht, sondern der Server sollte dem Client mitteilen, was zwischengespeichert werden muss oder nicht.
Archimedes Trajano
Ich stimme voll und ganz zu, dies muss ein richtiger Weg sein
smnbbrv
1

Das ist ein bisschen zu alt, aber: Lösungen wie sind veraltet. Lassen Sie den Server den Cache behandeln oder nicht (in der Antwort). Die einzige Möglichkeit, kein Caching zu gewährleisten (über neue Versionen in der Produktion nachzudenken), besteht darin, die js- oder css-Datei mit einer Versionsnummer zu ändern. Ich mache das mit Webpack.

Jens Alenius
quelle
1

Sie können auch in Ihrem Dienst versuchen, Header festzulegen, wie zum Beispiel:

...
{Injectable} aus "@ angle / core" importieren;
{HttpClient, HttpHeaders, HttpParams} aus "@ angle / common / http" importieren;
...
 @Injectable ()
Exportklasse MyService {

    private Header: HttpHeaders;


    Konstruktor (privater http: HttpClient ..) 
    {


        this.headers = new HttpHeaders ()
                    .append ("Content-Type", "application / json")
                    .append ("Accept", "application / json")
                    .append ("LanguageCulture", this.headersLanguage)
                    .append ("Cache-Control", "kein Cache")
                    .append ("Pragma", "kein Cache")                   
    }}
}}
....
Kein Name
quelle
0

Dieses Problem ist auf das IE-Caching-Problem zurückzuführen, das Sie gesagt haben. Sie können es im IE-Debug-Modus testen, indem Sie f12 drücken (dies funktioniert im Debug-Modus einwandfrei) .IE nimmt die Serverdaten nicht bei jedem Aufruf der Seite auf die Daten aus dem Cache. Führen Sie einen der folgenden Schritte aus, um dies zu deaktivieren:

  1. Fügen Sie Folgendes mit Ihrer http-Serviceanforderungs-URL hinzu

// Vorher (ausgestellt)

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

// Nachher (funktioniert gut)

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

  1. Deaktivieren Sie den Cache für das gesamte Modul: -

$ httpProvider.defaults.headers.common ['Pragma'] = 'kein Cache';

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

Ich habe dies gerade zu View hinzugefügt und es begann im IE zu arbeiten. Bestätigt für Angular 2.

Ingwer Bier
quelle
0

Eine Option besteht darin, den einfachen Ansatz zu verwenden, bei jeder Anforderung einen Zeitstempel hinzuzufügen, ohne dass der Cache geleert werden muss.

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

Versuchen Sie dies, es hat bei mir in einem ähnlichen Fall funktioniert: -

$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
quelle