2013-06-06 3 views
59

Ich benutze derzeit Service/$ Ressource, um AJAX-Aufrufe (GET in diesem Fall) zu machen, und IE speichert die Aufrufe im Cache, so dass keine neuen Daten vom Server abgerufen werden können. Ich habe eine Technik verwendet, die ich beim Googlen gefunden habe, um eine Zufallszahl zu erzeugen und sie an die Anfrage anzufügen, so dass IE nicht zum Cache für die Daten gehen wird.Bessere Möglichkeit, IE Cache in AngularJS zu verhindern?

Gibt es einen besseren Weg, als den CacheKill zu jeder Anfrage hinzuzufügen?

Werkscode

.factory('UserDeviceService', function ($resource) { 

     return $resource('/users/:dest', {}, { 
      query: {method: 'GET', params: {dest: "getDevicesByUserID"}, isArray: true } 
     }); 

Anruf von der Steuerung

$scope.getUserDevices = function() { 
     UserDeviceService.query({cacheKill: new Date().getTime()},function (data) { 
      //logic 
     }); 
    } 
+2

Ich habe No-Cache-Header auf der Server-Seite hinzugefügt und es funktionierte für jetzt. –

+1

Ufuk, das scheint der effektivste Weg zu sein, das Problem "global" oder besser skalierbar zu erledigen, ohne jeden Ajax/REST-Aufruf einzigartig machen zu müssen. Du solltest die Frage beantworten, damit ich sie als Antwort markieren kann! Du verdienst den Kredit. – binarygiant

+0

BTW, ich benutze node/express für den Webserver, und ich habe erreicht, was Ufuk empfohlen hat, indem ich den folgenden Code hinzufüge, um config: app.use (Funktion noCache (req, res, next)) { res.header ("Cache "Control", "no-cache, no-store, muss revidieren"); res.header ("Pragma", "no-cache"); res.header ("Läuft ab", 0); next (); }) – binarygiant

Antwort

33

Als binarygiant angefordert, poste ich meinen Kommentar als Antwort. Ich habe dieses Problem gelöst, indem ich der Antwort auf der Serverseite No-Cache-Header hinzugefügt habe. Beachten Sie, dass Sie dies nur für GET-Anfragen tun müssen, andere Anfragen scheinen gut zu funktionieren.

binarygiant geschrieben, wie Sie dies auf Node/Express tun können. Sie können es in ASP.NET MVC wie folgt tun:

+2

gibt es eine DRY-Implementierung von diesem? – meffect

+1

@meffect Hinzufügen als globaler Filter vielleicht? –

+0

es funktioniert für mich;) –

32

Aktivieren nocache in der ist Instanz war der beste Weg, um dies zu erreichen:

In Knoten/ausdrücken dies funktioniert zu verhindern IE von Caching diese Anforderungen:

app.use(function noCache(req, res, next) { 
    res.header("Cache-Control", "no-cache, no-store, must-revalidate"); 
    res.header("Pragma", "no-cache"); 
    res.header("Expires", 0); 
    next(); 
}); 
+0

Deaktiviert dies auch das Caching für statische Dateien? d. h. Ihr "öffentlicher" Ordner? –

+0

@Tony, fügen Sie einfach diese Middleware nach dem Servieren der statischen Dateien – Sentient

+0

danke hat gut funktioniert – Chris

-3

Eine offensichtliche Lösung ist die Verwendung von eindeutigen URLs. Aber wie können die Router-URLs nach der Initialisierung geändert werden? Das Deaktivieren von Browser-Caches ist keine Option, da wir diese für normale Operationen benötigen. Sie könnten Vorlagen aus dem $ templateCache entfernen, wenn diese nicht länger benötigt werden. (http://docs.angularjs.org/api/ng. $ TemplateCache). Diese neuen Dateien werden dem Cache hinzugefügt, sobald der Download abgeschlossen ist.

12

können Sie einen Interceptor hinzufügen, um eine eindeutige Anfrage-URL zu generieren. Auch kann entfernen Sie console.log ruft

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

Eine nettere Lösung, anstatt die URL zu manipulieren wäre: Überprüfen, ob die Anfrage Parameter 'config.params = config.params || hat [] 'und fügen Sie dann Ihren default noCache-Parameter' config.params ['noCache'] = new Date() hinzu. getTime(); ' – pasine

49

Wie in einem meiner anderen posts beschrieben, könnten Sie Caching deaktivieren global in der $ 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'; 
}]); 
+1

JSHint könnte sich über' $ httpProvider.defaults.headers.get ['Pragma'] = beschweren 'no-cache'; 'so ist es sicher, diese Zeile in' $ httpProvider.defaults.headers.get.Pragma = 'no-cache' zu ändern '' – yvesmancera

+0

Kann ich diese Extras nicht verwenden? – xlhuang

+1

Für diejenigen unter Ihnen, die Angular Resource verwenden, müssen Sie $ httpProvider durch $ resourceProvider ersetzen – James

4

ich es gelöst bekommen von:

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

God bless StackOverFlow! – SMir

33

Für diejenigen, die ASP.NET Web API 2 verwenden, wäre dies die äquivalente Lösung (Web API verwendet nicht die gleiche Caching-Logik wie MVC):

public class NoCacheHeaderFilter : ActionFilterAttribute 
{ 
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 
    { 
     if (actionExecutedContext.Response != null) // can be null when exception happens 
     { 
      actionExecutedContext.Response.Headers.CacheControl = 
       new CacheControlHeaderValue { NoCache = true, NoStore = true, MustRevalidate = true }; 
      actionExecutedContext.Response.Headers.Pragma.Add(new NameValueHeaderValue("no-cache")); 

      if (actionExecutedContext.Response.Content != null) // can be null (for example HTTP 400) 
      { 
       actionExecutedContext.Response.Content.Headers.Expires = DateTimeOffset.UtcNow; 
      } 
     } 
    } 
} 

befestigen Sie es dann in WebApiConfig.cs:

public static void Register(HttpConfiguration config) 
{ 
    .... 
    config.Filters.Add(new NoCacheHeaderFilter()); 

    config.Routes.MapHttpRoute(
     name: "DefaultApi", 
     routeTemplate: "api/{controller}/{id}", 
     defaults: new { id = RouteParameter.Optional } 
    ); 
} 
+4

Das hat unser Problem gelöst. Wir mussten auch 'if (actionExecutedContext.Request.Method.Method ==" GET ")' im Ereignis 'OnActionExecuted' hinzufügen, damit es nur bei GET-Anfragen ausgelöst wird. – RichardC

+0

Ich habe den Code für einige gefundene Randfälle aktualisiert. – UserControl

+3

Sie müssen mit der HttpMethod vergleichen und nicht nur die Zeichenfolge. Wie folgt: 'actionExecutedContext.Request.Method == HttpMethod.Get' –

3

Während dieser Ansatz:

myModule.config(['$httpProvider', function($httpProvider) { 
    //initialize get if not there 
    if (!$httpProvider.defaults.headers.get) { 
     $httpProvider.defaults.headers.get = {};  
    } 
    //disable IE ajax request caching 
    $httpProvider.defaults.headers.get['If-Modified-Since'] = '0'; 
}]); 

richtig ist, '0' ist kein gültiger Wert für die If-Modified-Since Header.Es muss eine gültige HTTP-date sein, zum Beispiel:

If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT 

Nach dem spec:

Ein Empfänger muss die If-Modified-Since-Header-Feld ignorieren, wenn die
erhält field- value ist kein gültiges HTTP-Datum, oder wenn die Methode
weder GET noch HEAD ist.

Also besser als sicher sein und ein tatsächliches Datum in der Vergangenheit verwenden.

Wenn Sie Kontrolle über die Serverausgabe haben, wäre es besser, stattdessen keine Zwischenspeicher-Header hinzuzufügen.

2

Meine Lösung war Cache-Control: no-cache Header auf dem Server hinzufügen, plus Hinzufügen von $templateCache.remove() vor dem Ändern des Status. Ich benutze angular-ui/ui-router. Ich hatte Probleme mit IE11 und Edge Browser.

$templateCache.remove('/partials/details.html'); 
$state.go('details'); 
+0

Meinst du Cache-Control: No-Cache? –

3

Koajs Äquivalent binarygiant Antwort:

app.use(route.get('*', noCache)); 

function* noCache(path, next){ 
    this.set('cache-control', 'no-cache, no-store, must-revalidate'); 
    this.set('pragma', 'no-cache'); 
    this.set('expires', 0); 
    yield next; 
} 
Verwandte Themen