Problème de mise en cache IE angulaire pour $ http

251

Tous les appels ajax envoyés depuis IE sont mis en cache par Angular et j'obtiens un 304 responsepour tous les appels suivants. Bien que la demande soit la même, la réponse ne sera pas la même dans mon cas. Je veux désactiver ce cache. J'ai essayé d'ajouter le cache attributeà $ http.get mais cela n'a toujours pas aidé. Comment résoudre ce problème?

Rahul
la source

Réponses:

439

Au lieu de désactiver la mise en cache pour chaque requête GET unique, je la désactive globalement dans $ 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
la source
78
L'en- If-Modified-Sincetête fait que IIS + iisnode lance 400 requêtes incorrectes pour chaque fichier html chargé via ngIncludeet ngView. Les deux en-têtes suivants ont cependant résolu le problème pour moi (je les ai retirés de Chrome, qui n'avait pas le problème de mise en cache): $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache'; $httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
Langdon
4
À mon avis, cette réponse devrait être marquée comme la réponse, alors que la solution fournie par Martin fonctionne, il s'agit plus d'un piratage que d'un correctif réel.
Robba
4
Cela a fonctionné pour mes demandes GET locales, mais cela a amené la seule demande CORS que je faisais à commencer à utiliser la méthode OPTIONS au lieu de la méthode GET. Le serveur tiers ne prend pas en charge la méthode OPTIONS, donc ma solution consiste à utiliser jQuery.get () pour effectuer cette demande et à utiliser $ scope.apply () dans les gestionnaires de réponses.
Ben
13
L'utilisation de l'en- If-Modified-Since = "0"tête rompt Tomcat (problème avec l'analyse de la date de l'en-tête, car la 0valeur RFC n'est pas valide ). Correction de l'utilisation de la valeur à la Mon, 26 Jul 1997 05:00:00 GMTplace.
lopisan
6
Je n'ai pas utilisé l'en-tête "If-Modified-Since" et cela a fonctionné sans cela. Seuls les deux autres sont nécessaires.
Michael Mahony
69

Vous pouvez soit ajouter une chaîne de requête unique (je crois que c'est ce que jQuery fait avec l'option cache: false) à la demande.

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

Une solution peut-être meilleure est que si vous avez accès au serveur, vous pouvez vous assurer que les en-têtes nécessaires sont définis pour empêcher la mise en cache. Si vous utilisez ASP.NET MVC cette réponse, cela pourrait vous aider.

Martin
la source
2
$http.get(url+ "?"+new Date().toString())est juste une autre représentation, sans utiliser de paramètre mais en l'ajoutant à la chaîne de requête.
Davut Gürbüz
28

vous pouvez ajouter un intercepteur.

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

vous devez supprimer les lignes console.log après vérification.

dillip pattnaik
la source
Et vous devriez les utiliser $logau cas où vous oublieriez de les retirer.
Carl G
2
J'ai de sérieux problèmes de mise en cache dans IE, ce qui conduit à une page blanche, car des parties importantes ne se sont pas exécutées. L'utilisation de l'intercepteur proposé a résolu ce problème! +1
raoulinski
Je pense que c'est la meilleure approche, car elle évite les problèmes avec le comportement de CORS et IE de déclencher une demande de contrôle en amont si vous ajoutez des en-têtes supplémentaires. Cela semble être la méthode la plus sûre pour ne pas rencontrer de problèmes supplémentaires
chrismarx
@dilip pattnaik: - Pourquoi ce problème se produit avec angular et ie?
MiHawk
14

J'ai simplement ajouté trois balises META dans index.html sur un projet angulaire et le problème de cache a été résolu sur 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
la source
2
Nous avions déjà ces balises META dans notre index.htmllorsque nous avons remarqué qu'IE11 mettait en cache les demandes AJAX: / ​​Mais la configuration $httpProvidercomme indiqué dans d'autres réponses a bien fonctionné.
walen
14

Dupliquer ma réponse dans un autre fil .

Pour Angular 2 et plus récent , la façon la plus simple d'ajouter des en- no-cachetêtes en remplaçant 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'
    });
}

Et référencez-le dans votre module:

@NgModule({
    ...
    providers: [
        ...
        { provide: RequestOptions, useClass: CustomRequestOptions }
    ]
})
Vitaliy Ulantikov
la source
Ne s'agiraient-ils pas d'en-têtes pour la réponse du serveur, pas pour la demande du navigateur? (Je pourrais imaginer que l'on pourrait fixer If-Modified-Sinceune date dans le passé en utilisant la méthode ci-dessus.)
Arjan
@Vitaliy: - Pourquoi ce problème se produit avec angulaire et ie?
MiHawk
Votre approche supprimera tous les en-têtes personnalisés déjà présents. Par conséquent, procédez comme suit au lieu de créer un nouvel objet En-tête. 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

La garantie que je travaillais était quelque chose dans ce sens:

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

Je devais fusionner deux des solutions ci - dessus afin de garantir l'utilisation correcte pour toutes les méthodes, mais vous pouvez remplacer commonpar getou une autre méthode par exemple put, post, deletepour faire ce travail pour les cas différents.

marksyzm
la source
pouvez-vous me dire où dans le code vous avez ajouté ceci au fichier angular.js? quelle ligne #?
JonathanScialpi
@JonathanScialpi Je l'ai mis à jour pour montrer où je pourrais le mettre. Son emplacement dans la fonction anonyme ne devrait pas avoir d'importance.
marksyzm
@marksyzm peut u plzz me dire quel est le sens de cette ligneif (!$httpProvider.defaults.headers.get) { $httpProvider.defaults.headers.common = {}; }
Monojit Sarkar
@MonojitSarkar Ah, c'était censé être headers.common dans la déclaration if, merci pour ce pointeur
marksyzm
1
["If-Modified-Since"] = "0"est illégal et génère une mauvaise demande sur certains backends. ce devrait être une date.
jenson-button-event
8

Cette seule ligne m'a aidé (Angular 1.4.8):

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

UPD: Le problème est qu'IE11 fait une mise en cache agressive. Lorsque je regardais Fiddler, j'ai remarqué qu'en mode F12, les requêtes envoyaient "Pragma = no-cache" et le point final était demandé à chaque fois que je visitais une page. Mais en mode normal, le point de terminaison n'a été demandé qu'une seule fois lors de ma première visite sur la page.

yamaxim
la source
1
Juste pour info, cette réponse a causé un problème CORS lors de la demande de fichiers à partir du stockage blob d'Azure, difficile à retrouver, mais a finalement compris que c'était la cause. La suppression de l'en-tête pragma a résolu mon problème CORS (mais a rétabli le problème de mise en cache IE).
keithl8041
7

Pour éviter la mise en cache, une option consiste à donner une URL différente pour la même ressource ou les mêmes données. Pour générer une URL différente, vous pouvez ajouter une chaîne de requête aléatoire à la fin de l'URL. Cette technique fonctionne pour les requêtes JQuery, Angular ou autre type ajax.

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

Je le résout en ajoutant datetime comme un nombre aléatoire:

$http.get("/your_url?rnd="+new Date().getTime()).success(function(data, status, headers, config) {
    console.log('your get response is new!!!');
});
khichar.anil
la source
: - Pourquoi ce problème se produit avec angulaire et ie?
MiHawk
4

La solution ci-dessus fonctionnera (rendre l'url unique en ajoutant dans la chaîne de requête un nouveau paramètre) mais je préfère la solution proposée [ici]: une meilleure façon de prévenir le cache IE dans AngularJS?, qui gère cela au niveau du serveur car il n'est pas spécifique à IE. Je veux dire, si cette ressource ne doit pas être mise en cache, faites-le sur le serveur (cela n'a rien à voir avec le navigateur utilisé; c'est intrinsèque à la ressource).

Par exemple, en java avec JAX-RS, faites-le par programme pour JAX-RS v1 ou de manière déclinative pour JAX-RS v2.

Je suis sûr que tout le monde saura comment le faire

rguitter
la source
1
Bien qu'il puisse être élaboré, c'est la bonne façon de le faire. Le côté client ne doit pas choisir quoi mettre en cache ou non, mais ce doit être le serveur qui doit dire au client ce qui doit être mis en cache ou non.
Archimedes Trajano
Je suis entièrement d'accord, cela doit être une bonne façon
smnbbrv
1

C'est un peu ancien mais: les solutions comme sont obsolètes. Laissez le serveur gérer le cache ou non le cache (dans la réponse). La seule façon de garantir l'absence de mise en cache (en pensant aux nouvelles versions en production) est de changer le fichier js ou css avec un numéro de version. Je fais cela avec webpack.

Jens Alenius
la source
1

vous pouvez également essayer dans votre service de définir des en-têtes comme par exemple:

...
importer {Injectable} depuis "@ angular / core";
importer {HttpClient, HttpHeaders, HttpParams} depuis "@ angular / common / http";
...
 @Injectable ()
classe d'exportation MyService {

    en-têtes privés: HttpHeaders;


    constructeur (http privé: HttpClient ..) 
    {


        this.headers = nouveaux HttpHeaders ()
                    .append ("Content-Type", "application / json")
                    .append ("Accepter", "application / json")
                    .append ("LanguageCulture", this.headersLanguage)
                    .append ("Cache-Control", "no-cache")
                    .append ("Pragma", "no-cache")                   
    }
}
....
Sans nom
la source
0

Ce problème est dû au problème de mise en cache IE comme vous l'avez dit, vous pouvez le tester en mode de débogage IE en appuyant sur f12 (cela fonctionnera bien en mode débogage) .IE ne prendra pas les données du serveur à chaque fois que la page appelle, cela prend les données du cache. Pour désactiver cela, effectuez l'une des opérations suivantes:

  1. ajoutez ce qui suit avec votre URL de demande de service http

// Avant (délivré un)

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

// Après (fonctionne bien)

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

  1. désactiver le cache pour l'ensemble du module: -

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

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

Je viens de l'ajouter à View et il a commencé à fonctionner sur IE. Confirmé de travailler sur Angular 2.

Bière de gingembre
la source
0

Une option consiste à utiliser l'approche simple consistant à ajouter un horodatage à chaque demande, pas besoin de vider le cache.

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

Essayez ceci, cela a fonctionné pour moi dans un cas similaire: -

$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
la source