Mettre en cache une réponse de service HTTP «Get» dans AngularJS?


211

Je veux pouvoir créer un service AngularJS personnalisé qui effectue une demande HTTP «Get» lorsque son objet de données est vide et remplit l'objet de données en cas de succès.

La prochaine fois qu'un appel est effectué vers ce service, je voudrais contourner le surcoût lié à la nouvelle demande HTTP et retourner à la place l'objet de données mis en cache.

Est-ce possible?

Réponses:


315

Le $ http d' Angular a un cache intégré . Selon les documents:

cache - {boolean | Object} - Une valeur booléenne ou un objet créé avec $ cacheFactory pour activer ou désactiver la mise en cache de la réponse HTTP. Voir $ http Caching pour plus d'informations .

Valeur booléenne

Ainsi , vous pouvez définir cacheà vrai dans ses options:

$http.get(url, { cache: true}).success(...);

ou, si vous préférez le type d'appel de configuration:

$http({ cache: true, url: url, method: 'GET'}).success(...);

Objet de cache

Vous pouvez également utiliser une fabrique de cache:

var cache = $cacheFactory('myCache');

$http.get(url, { cache: cache })

Vous pouvez l'implémenter vous-même à l'aide de $ cacheFactory (en particulier lorsque vous utilisez $ resource):

var cache = $cacheFactory('myCache');

var data = cache.get(someKey);

if (!data) {
   $http.get(url).success(function(result) {
      data = result;
      cache.put(someKey, data);
   });
}

47
Question: quel est l'intérêt d'enregistrer les données mises en cache dans $ cacheFactory .. pourquoi ne pas simplement les enregistrer dans un objet local dans le service? Des bonnes raisons?
Spock

7
Regarde ça. Il vous donne beaucoup de personnalisation, y compris le support localStorage, le support de délai d'attente, toutes sortes de goodies http://jmdobry.github.io/angular-cache/
Erik Donohoo

4
Je suis particulièrement curieux de savoir le code d'état 304 - le cache du navigateur fonctionne-t-il sans activer le cache: vrai? Sinon, le cache: true le fait-il fonctionner? La mise en cache est-elle permanente ou se trouve-t-elle uniquement dans la RAM et est-elle déchargée lorsque la page est fermée?
sasha.sochka

3
Est-il possible de spécifier une limite de temps sur ce cache sans l'implémenter manuellement?
Mark

11
@Spock, $ cacheFactory lui-même est un service qui peut être utilisé sur plusieurs contrôleurs et composants angulaires. Il peut être utilisé comme un service api générique pour mettre en cache tous vos $ http dans un seul objet de service plutôt que d'avoir des objets de service différents pour chacun d'eux.
Nirav Gandhi

48

Je pense qu'il y a un moyen encore plus facile maintenant. Cela permet la mise en cache de base pour toutes les requêtes $ http (dont $ resource hérite):

 var app = angular.module('myApp',[])
      .config(['$httpProvider', function ($httpProvider) {
            // enable http caching
           $httpProvider.defaults.cache = true;
      }])

46
Vous voulez à peine mettre en cache chaque requête http unique. Je ne vois pas quand ce sera le cas?
Spock

1
Chaque application / module est différent, non?!
rodrigo-silveira

13
Si vous souhaitez mettre en cache la majorité des demandes, la définition de la valeur par défaut sur true est pratique.
Adrian Lynch

12

Un moyen plus simple de le faire dans la version stable actuelle (1.0.6) nécessite beaucoup moins de code.

Après avoir configuré votre module, ajoutez une usine:

var app = angular.module('myApp', []);
// Configure routes and controllers and views associated with them.
app.config(function ($routeProvider) {
    // route setups
});
app.factory('MyCache', function ($cacheFactory) {
    return $cacheFactory('myCache');
});

Vous pouvez maintenant transmettre ceci à votre contrôleur:

app.controller('MyController', function ($scope, $http, MyCache) {
    $http.get('fileInThisCase.json', { cache: MyCache }).success(function (data) {
        // stuff with results
    });
});

Un inconvénient est que les noms des clés sont également configurés automatiquement, ce qui pourrait rendre leur effacement difficile. J'espère qu'ils ajouteront d'une manière ou d'une autre des noms clés.


7

Consultez le cache angulaire de la bibliothèque si vous aimez la mise en cache intégrée de $ http mais souhaitez plus de contrôle. Vous pouvez l'utiliser pour augmenter de manière transparente le cache $ http avec des purges périodiques de durée de vie et la possibilité de conserver le cache sur localStorage afin qu'il soit disponible sur toutes les sessions.

FWIW, il fournit également des outils et des modèles pour transformer votre cache en une sorte de magasin de données plus dynamique avec laquelle vous pouvez interagir en tant que POJO, plutôt que simplement les chaînes JSON par défaut. Je ne peux pas encore commenter l'utilité de cette option.

(Ensuite, en plus de cela, les données angulaires de bibliothèque associées remplacent en quelque sorte $ resource et / ou Restangular, et dépendent de angular-cache.)


3
Veuillez noter que angular-datac'est obsolète maintenant. Le dernier en date est js-data-angular js-data.io/v1.8.0/docs/js-data-angular
demisx

La bibliothèque angular-cache possède les fonctionnalités qui auraient dû être intégrées à $ cacheFactory d'Angular. La solution intégrée semble presque inutile étant donné ses limites dans la possibilité d'expiration de caches spécifiques. L'usine de cache angulaire était également l'une des bibliothèques tierces les plus faciles à implémenter.
Darryl

5

Comme les usines AngularJS sont des singletons , vous pouvez simplement stocker le résultat de la requête http et le récupérer la prochaine fois que votre service est injecté dans quelque chose.

angular.module('myApp', ['ngResource']).factory('myService',
  function($resource) {
    var cache = false;
    return {
      query: function() {
        if(!cache) {
          cache = $resource('http://example.com/api').query();
        }
        return cache;
      }
    };
  }
);

J'ai une question sur la façon de vérifier si GET a échoué et dans ce cas de ne pas mettre en cache la ressource $ resource ... query ()
robert

@robert vous pouvez vérifier le deuxième argument de la méthode .then ou mieux encore, utiliser le rappel .catch. Par exemple $ http .get (url) .then (successCallback, failCallback) ou $ http .get (url) .then (successCallback, failCallback) .catch (errorCallback) Le rappel d'erreur sera exécuté même si quelque chose de mal se produit dans le failCallback , bien qu'il soit plus courant d'éviter tout échec de rappel et d'utiliser .then (success) .catch (manageRequestFail). J'espère que cela vous aidera à saisir l'idée, plus d'informations dans la documentation angulaire $ http.
Faito

2
angularBlogServices.factory('BlogPost', ['$resource',
    function($resource) {
        return $resource("./Post/:id", {}, {
            get:    {method: 'GET',    cache: true,  isArray: false},
            save:   {method: 'POST',   cache: false, isArray: false},
            update: {method: 'PUT',    cache: false, isArray: false},
            delete: {method: 'DELETE', cache: false, isArray: false}
        });
    }]);

définissez le cache sur true.


Ce serait aussi sûr que l'application cliente avec le navigateur lui-même comme n'importe quelle autre application Web.
bhantol

-1

Dans Angular 8, nous pouvons faire comme ceci:

import { Injectable } from '@angular/core';
import { YourModel} from '../models/<yourModel>.model';
import { UserService } from './user.service';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})

export class GlobalDataService {

  private me: <YourModel>;

  private meObservable: Observable<User>;

  constructor(private yourModalService: <yourModalService>, private http: HttpClient) {

  }

  ngOnInit() {

  }


  getYourModel(): Observable<YourModel> {

    if (this.me) {
      return of(this.me);
    } else if (this.meObservable) {
      return this.meObservable;
    }
    else {
      this.meObservable = this.yourModalService.getCall<yourModel>() // Your http call
      .pipe(
        map(data => {
          this.me = data;
          return data;
        })
      );
      return this.meObservable;
    }
  }
}

Vous pouvez l'appeler comme ceci:

this.globalDataService.getYourModel().subscribe(yourModel => {


});

Le code ci-dessus mettra en cache le résultat de l'API distante au premier appel afin qu'il puisse être utilisé sur d'autres demandes à cette méthode.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.