Кэшировать ответ службы HTTP 'Get' в AngularJS?

211

Я хочу иметь возможность создавать пользовательский сервис AngularJS, который делает HTTP-запрос «Get», когда его объект данных пуст и заполняет объект данных в случае успеха.

В следующий раз, когда будет сделан вызов этой службе, я бы хотел обойти накладные расходы при повторном выполнении HTTP-запроса и вместо этого вернуть кешированный объект данных.

Это возможно?

Gavriguy
источник

Ответы:

315

$ Http Angular имеет встроенный кеш . Согласно документам:

cache - {boolean | Object} - логическое значение или объект, созданные с помощью $ cacheFactory для включения или отключения кэширования ответа HTTP. Смотрите $ http Caching для получения дополнительной информации .

Логическое значение

Таким образом, вы можете установить cacheзначение true в его опциях:

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

или, если вы предпочитаете тип конфигурации вызова:

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

Cache Object

Вы также можете использовать фабрику кеша:

var cache = $cacheFactory('myCache');

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

Вы можете реализовать это самостоятельно, используя $ cacheFactory (особенно удобно при использовании $ resource):

var cache = $cacheFactory('myCache');

var data = cache.get(someKey);

if (!data) {
   $http.get(url).success(function(result) {
      data = result;
      cache.put(someKey, data);
   });
}
asgoth
источник
47
Вопрос: какой смысл сохранять кэшированные данные в $ cacheFactory .. почему бы просто не сохранить их в локальном объекте в Сервисе? Есть веские причины?
Спок
7
Проверь это. Он дает вам множество возможностей настройки, включая поддержку localStorage, поддержку тайм-аута, всевозможные вкусности http://jmdobry.github.io/angular-cache/
Эрик Доноху,
4
Меня особенно интересует код состояния 304 - работает ли кеш браузера без включения кеша: верно? Если нет, то работает ли cache: true? Кэширование постоянное или оно только в оперативной памяти и выгружается при закрытии страницы?
sasha.sochka
3
Любой способ указать ограничение по времени для этого кэша без ручной реализации?
Mark
11
@Spock, $ cacheFactory сам по себе является сервисом, который можно использовать на нескольких контроллерах и угловых компонентах. Он может использоваться как универсальный API-сервис для кэширования всех ваших $ http в один сервисный объект, вместо того, чтобы иметь разные сервисные объекты для каждого из них.
Нирав Ганди
48

Я думаю, что теперь есть еще более легкий путь. Это включает базовое кэширование для всех запросов $ http (которые наследует $ resource):

 var app = angular.module('myApp',[])
      .config(['$httpProvider', function ($httpProvider) {
            // enable http caching
           $httpProvider.defaults.cache = true;
      }])
gspatel
источник
46
Вы вряд ли захотите кэшировать каждый http-запрос. Я не понимаю, когда это когда-нибудь случится?
Спок
1
Каждое приложение / модуль отличается, нет ?!
Родриго-Силвейра,
13
Если вы хотите кэшировать большинство запросов, тогда удобно установить значение по умолчанию true.
Эдриан Линч
12

Более простой способ сделать это в текущей стабильной версии (1.0.6) требует намного меньше кода.

После настройки вашего модуля добавьте фабрику:

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

Теперь вы можете передать это в свой контроллер:

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

Недостатком является то, что имена ключей также настраиваются автоматически, что может затруднить их очистку. Надеюсь, они каким-то образом добавят имена ключей.

Джеймс Скемп
источник
7

Посмотрите библиотеку angular-cache, если вам нравится встроенное кэширование $ http, но вы хотите больше контроля. Вы можете использовать его для плавного увеличения кеша $ http с помощью периодических очисток времени жизни и возможностью сохранения кеша в localStorage, чтобы он был доступен между сеансами.

Кроме того, он также предоставляет инструменты и шаблоны для превращения вашего кэша в более динамичный тип хранилища данных, с которым вы можете взаимодействовать как POJO, а не просто строки JSON по умолчанию. Пока не можете комментировать полезность этой опции.

(Кроме того, связанные с ними угловые данные библиотеки являются своего рода заменой $ resource и / или Restangular и зависят от angular-cache.)

XML
источник
3
Обратите внимание, что angular-dataэто устарело сейчас. Последний js-data-angular выпуск
demisx
Библиотека angular-cache имеет функции, которые должны были быть встроены в Angular $ cacheFactory. Встроенное решение кажется почти бесполезным, учитывая его ограничения в возможности истечения срока действия определенных кэшей. Фабрика angular-cache также была одной из самых простых сторонних библиотек.
Дэррил
5

Поскольку фабрики AngularJS являются синглетонами , вы можете просто сохранить результат http-запроса и получить его в следующий раз, когда ваш сервис будет введен во что-то.

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;
      }
    };
  }
);
Rimian
источник
У меня есть один вопрос, как проверить, не удалось ли GET, и в этом случае не помещать в кеш запрос $ resource ... query ()
robert
@robert вы можете проверить второй аргумент метода .then или, что еще лучше, использовать обратный вызов .catch. Например, $ http .get (url) .then (successCallback, failCallback) или $ http .get (url) .then (successCallback, failCallback) .catch (errorCallback). Обратный вызов ошибки будет выполнен, даже если в failCallback произойдет что-то плохое. , хотя чаще избегать обратного вызова с ошибками и использовать .then (success) .catch (manageRequestFail). Надеюсь, что это поможет понять идею, больше информации в англоязычной документации $ 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}
        });
    }]);

установить кеш на true

Howardyan
источник
Это было бы так же безопасно, как и клиентское приложение без самого браузера, как любое другое веб-приложение.
Бхантол
-1

В Angular 8 мы можем сделать так:

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

Вы можете назвать это так:

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


});

Приведенный выше код будет кэшировать результат удаленного API при первом вызове, чтобы его можно было использовать при дальнейших запросах к этому методу.

Raghav
источник