Kątowy problem buforowania IE dla $ http

251

Wszystkie wywołania ajax, które są wysyłane z IE, są buforowane przez Angular i otrzymuję 304 responsedla wszystkich kolejnych wywołań. Chociaż żądanie jest takie samo, odpowiedź nie będzie taka sama w moim przypadku. Chcę wyłączyć tę pamięć podręczną. Próbowałem dodać cache attributedo $ http.get, ale nadal nie pomogło. Jak rozwiązać ten problem?

Rahul
źródło

Odpowiedzi:

439

Zamiast wyłączać buforowanie dla każdego pojedynczego żądania GET, wyłączam je globalnie w $ 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
źródło
78
Te If-Modified-Sincemarki header IIS + rzut iisnode 400 Bad Request dla każdego pliku html załadowane przez ngIncludea ngView. Następujące dwa nagłówki naprawiły jednak dla mnie problem (ściągnąłem je z Chrome, który nie miał problemu z buforowaniem): $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache'; $httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
Langdon 5'14
4
Moim zdaniem odpowiedź ta powinna zostać oznaczona jako odpowiedź, podczas gdy rozwiązanie dostarczone przez Martina działa, jest to raczej hack niż faktyczna poprawka.
Robba
4
Działa to w przypadku moich lokalnych żądań GET, ale spowodowało, że jedno żądanie CORS, które wysyłałem, zaczęło używać metody OPTIONS zamiast metody GET. Serwer innej firmy nie obsługuje metody OPTIONS, więc moim obejściem jest użycie jQuery.get () do wykonania tego żądania i użycie $ scope.apply () w procedurach obsługi odpowiedzi.
Ben
13
Użycie If-Modified-Since = "0"nagłówka powoduje uszkodzenie Tomcat (problem z analizą daty nagłówka, ponieważ 0nie jest to poprawna wartość RFC ). Naprawiono Mon, 26 Jul 1997 05:00:00 GMTzamiast tego używanie wartości .
lopisan
6
Nie użyłem nagłówka „If-Modified-Since” i zadziałało bez tego. Potrzebne są tylko pozostałe dwa.
Michael Mahony,
69

Możesz dołączyć do zapytania unikalny kwerenda (uważam, że to właśnie robi jQuery z opcją cache: false).

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

Być może lepszym rozwiązaniem jest, jeśli masz dostęp do serwera, możesz upewnić się, że ustawione są niezbędne nagłówki, aby zapobiec buforowaniu. Jeśli używasz ASP.NET MVC tej odpowiedzi, może pomóc.

Jaskółka oknówka
źródło
2
$http.get(url+ "?"+new Date().toString())jest po prostu kolejną reprezentacją, bez użycia parametru, ale dodając go do ciągu zapytania.
Davut Gürbüz
28

możesz dodać przechwytywacz.

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

powinieneś usunąć wiersze console.log po weryfikacji.

Dillip Pattnaik
źródło
I powinieneś używać $logna wypadek, gdybyś zapomniał je wyjąć.
Carl G
2
Mam poważne problemy z buforowaniem w IE, co prowadzi do pustej strony, ponieważ ważne części nie zostały wykonane. Korzystanie z proponowanego przechwytywacza rozwiązało ten problem! +1
raoulinski
Myślę, że jest to najlepsze podejście, ponieważ pozwala uniknąć problemów z zachowaniem CORS i IE w wyzwalaniu żądania inspekcji wstępnej, jeśli dodasz dodatkowe nagłówki. To wydaje się być najbezpieczniejszą metodą, aby nie napotkać dodatkowych problemów
chrismarx
@dilip pattnaik: - Dlaczego ten problem występuje z kątowym i ie?
MiHawk,
14

Po prostu dodałem trzy metatagi do index.html w projekcie kątowym, a problem pamięci podręcznej został rozwiązany w 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
źródło
2
Mieliśmy już te metatagi, index.htmlgdy zauważyliśmy, że IE11 buforuje żądania AJAX: / ​​Ale konfigurowanie, $httpProviderjak pokazano w innych odpowiedziach, działało dobrze.
wal
14

Duplikuję moją odpowiedź w innym wątku .

W Angular 2 i nowszych najłatwiejszym sposobem dodawania no-cachenagłówków przez przesłonięcie 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'
    });
}

I odwołaj się do tego w swoim module:

@NgModule({
    ...
    providers: [
        ...
        { provide: RequestOptions, useClass: CustomRequestOptions }
    ]
})
Vitaliy Ulantikov
źródło
Czy nie byłyby to nagłówki odpowiedzi serwera, a nie żądania przeglądarki? (Mogłem sobie wyobrazić, że można ustawić If-Modified-Sincedatę z daleka w przeszłości przy użyciu powyższej metody.)
Arjan
@Vitaliy: - Dlaczego ten problem występuje z kątowym i ie?
MiHawk,
Twoje podejście usunie wszystkie niestandardowe nagłówki, które już tam są. Dlatego wykonaj następujące czynności zamiast tworzenia nowego obiektu 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

Gwarantowany, który miałem pracować, był w następujący sposób:

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

Musiałem połączyć 2 z powyższych rozwiązań w celu zagwarantowania właściwego wykorzystania dla wszystkich metod, ale można zastąpić commonz getlub inna metoda czyli put, post, deleteaby dokonać tej pracy w różnych przypadkach.

marksyzm
źródło
czy możesz mi powiedzieć, gdzie w kodzie dodałeś to do pliku angular.js? jaka linia #?
JonathanScialpi
@JathanathanScialpi Zaktualizowałem go, aby pokazać, gdzie mogę go umieścić. Gdzie jest w ramach funkcji anonimowej nie powinno mieć znaczenia.
marksyzm
@marksyzm czy możesz mi powiedzieć, jakie jest znaczenie tej liniiif (!$httpProvider.defaults.headers.get) { $httpProvider.defaults.headers.common = {}; }
Monojit Sarkar
@MonojitSarkar Ah, to miało być nagłówki. Często w instrukcji if, dzięki za ten wskaźnik
marksyzm
1
["If-Modified-Since"] = "0"jest nielegalne i generuje nieprawidłowe żądanie na niektórych zapleczach. to powinna być randka.
jenson-button-event
8

Ta jedyna linia pomogła mi (Angular 1.4.8):

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

UPD: Problem polega na tym, że IE11 wykonuje agresywne buforowanie. Kiedy szukałem Fiddlera, zauważyłem, że w trybie F12 żądania wysyłają „Pragma = brak pamięci podręcznej”, a punkt końcowy jest wymagany za każdym razem, gdy odwiedzam stronę. Ale w trybie normalnym punkt końcowy został zażądany tylko raz przy pierwszej wizycie na stronie.

yamaxim
źródło
1
Tylko do wiadomości, ta odpowiedź spowodowała problem CORS podczas żądania plików z magazynu obiektów blob platformy Azure, trudny do wyśledzenia, ale w końcu zorientował się, że to jest przyczyną. Usunięcie nagłówka pragma naprawiło mój problem CORS (ale przywróciło problem buforowania IE).
keithl8041,
7

Aby uniknąć buforowania, jedną z opcji jest podanie innego adresu URL dla tego samego zasobu lub danych. Aby wygenerować inny adres URL, możesz dodać losowy ciąg zapytania na końcu adresu URL. Ta technika działa w przypadku zapytań JQuery, Angular lub innego typu ajax.

myURL = myURL +"?random="+new Date().getTime();
Razan Paul
źródło
6

Rozumiem, że dołączam datetime jako liczbę losową:

$http.get("/your_url?rnd="+new Date().getTime()).success(function(data, status, headers, config) {
    console.log('your get response is new!!!');
});
khichar.anil
źródło
: - Dlaczego ten problem występuje z kątowym i tj.?
MiHawk,
4

Powyższe rozwiązanie będzie działać (uczynić adres URL unikalnym, dodając w zapytaniu nowy parametr), ale wolę zaproponować rozwiązanie [tutaj]: Lepszy sposób na zapobieganie pamięci podręcznej IE w AngularJS?, które obsługują to na poziomie serwera, ponieważ nie jest to specyficzne dla IE. Mam na myśli, że jeśli ten zasób nie powinien być buforowany, zrób to na serwerze (nie ma to nic wspólnego z używaną przeglądarką; jest ingerujący w zasób).

Na przykład w Javie z JAX-RS zrób to programowo dla JAX-RS v1 lub deklatacyjnie dla JAX-RS v2.

Jestem pewien, że ktoś wymyśli, jak to zrobić

rguitter
źródło
1
Chociaż można to opracować, jest to właściwy sposób na zrobienie tego. Po stronie klienta nie powinno się wybierać, co ma być buforowane, czy nie, ale to serwer powinien powiedzieć klientowi, co należy buforować, czy nie.
Archimedes Trajano,
W pełni się zgadzam, to musi być właściwy sposób
smnbbrv
1

To trochę za stare, ale: Rozwiązania takie są przestarzałe. Pozwól serwerowi obsługiwać pamięć podręczną lub nie pamięć podręczną (w odpowiedzi). Jedynym sposobem na zagwarantowanie braku buforowania (myślenie o nowych wersjach w produkcji) jest zmiana pliku js lub css za pomocą numeru wersji. Robię to za pomocą webpacka.

Jens Alenius
źródło
1

możesz także spróbować w swoim serwerze ustawić nagłówki, takie jak na przykład:

...
import {Injectable} z „@ angular / core”;
import {HttpClient, HttpHeaders, HttpParams} z „@ angular / common / http”;
...
 @Injectable ()
klasa eksportu MyService {

    prywatne nagłówki: HttpHeaders;


    Konstruktor (prywatny http: HttpClient ..) 
    {


        this.headers = new HttpHeaders ()
                    .append („Content-Type”, „application / json”)
                    .append („Accept”, „application / json”)
                    .append („LanguageCulture”, this.headersLanguage)
                    .append („Cache-Control”, „no-cache”)
                    .append („Pragma”, „bez pamięci podręcznej”)                   
    }
}
…
Bez nazwy
źródło
0

Ten problem wynika z problemu buforowania IE, jak powiedziałeś, możesz go przetestować w trybie debugowania IE, naciskając klawisz f12 (będzie działał dobrze w trybie debugowania). IIE nie pobierze danych serwera za każdym razem, gdy strona wywołuje, zajmuje dane z pamięci podręcznej. Aby to wyłączyć, wykonaj jedną z następujących czynności:

  1. dołącz do swojego adresu URL żądania usługi http następujące

// Przed (wydany)

this.httpService.get (this.serviceUrl + "/eAMobileService.svc/ValidateEngagmentName/" + nazwa zaangażowania, {})

// Po (działa dobrze)

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

  1. wyłącz pamięć podręczną dla całego modułu: -

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

Nijas_kp
źródło
0
meta http-equiv="Cache-Control" content="no-cache"

Właśnie dodałem to do widoku i zaczęło działać w IE. Potwierdzony do pracy nad Angular 2.

Piwo imbirowe
źródło
0

Opcją jest zastosowanie prostego podejścia polegającego na dodawaniu znacznika czasu do każdego żądania bez potrzeby czyszczenia pamięci podręcznej.

    let c=new Date().getTime();
    $http.get('url?d='+c)
Vaimeo
źródło
-2

Spróbuj tego, zadziałało dla mnie w podobnym przypadku: -

$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
źródło