Armazenar em cache uma resposta de serviço HTTP 'Get' no AngularJS?

211

Quero poder criar um serviço AngularJS personalizado que faça uma solicitação HTTP 'Get' quando seu objeto de dados estiver vazio e preencha o objeto de dados com êxito.

Na próxima vez que uma chamada for feita para esse serviço, eu gostaria de ignorar a sobrecarga de fazer a solicitação HTTP novamente e, em vez disso, retornar o objeto de dados em cache.

Isso é possível?

Gavriguy
fonte

Respostas:

315

O $ http da Angular possui um cache incorporado . De acordo com os documentos:

cache - {boolean | Object} - Um valor ou objeto booleano criado com $ cacheFactory para ativar ou desativar o armazenamento em cache da resposta HTTP. Consulte Cache de $ http para obter mais informações .

Valor booleano

Assim, você pode definir cachecomo true em suas opções:

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

ou, se você preferir o tipo de configuração de chamada:

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

Objeto de cache

Você também pode usar uma fábrica de cache:

var cache = $cacheFactory('myCache');

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

Você pode implementá-lo usando o $ cacheFactory (especialmente ao usar o recurso $):

var cache = $cacheFactory('myCache');

var data = cache.get(someKey);

if (!data) {
   $http.get(url).success(function(result) {
      data = result;
      cache.put(someKey, data);
   });
}
asgoth
fonte
47
Pergunta: qual é o objetivo de salvar dados em cache no $ cacheFactory .. por que não salvá-los em um objeto local no Serviço? Alguma boa razão?
Spock
7
Veja isso. Ele lhe dá muita customização, incluindo suporte localStorage, suporte de tempo limite, todos os tipos de guloseimas http://jmdobry.github.io/angular-cache/
Erik Donohoo
4
Estou especialmente curioso sobre o código de status 304 - o cache do navegador funciona sem ativar o cache: true? Caso contrário, o cache: true o faz funcionar? O cache é permanente ou está apenas na RAM e é descarregado quando a página é fechada?
Sasha.sochka
3
Alguma maneira de especificar um limite de tempo nesse cache sem implementá-lo manualmente?
Mark
11
@Spock, o próprio $ cacheFactory é um serviço que pode ser usado em vários controladores e componentes angulares. Ele pode ser usado como um serviço API genérico para armazenar em cache todos os seus $ http em um único objeto de serviço, em vez de ter objetos de serviço diferentes para cada um deles.
Nirav Gandhi
48

Eu acho que há uma maneira ainda mais fácil agora. Isso permite o armazenamento em cache básico para todas as solicitações $ http (que $ resource herda):

 var app = angular.module('myApp',[])
      .config(['$httpProvider', function ($httpProvider) {
            // enable http caching
           $httpProvider.defaults.cache = true;
      }])
gspatel
fonte
46
Você quase não deseja armazenar em cache todas as solicitações HTTP. Não vejo quando isso aconteceria?
Spock
1
Cada aplicativo / módulo é diferente, não ?!
Rodrigo-silveira
13
Se você deseja armazenar em cache a maioria dos pedidos, definir o padrão como true é útil.
Adrian Lynch
12

Uma maneira mais fácil de fazer isso na versão estável atual (1.0.6) requer muito menos código.

Depois de configurar seu módulo, adicione uma fábrica:

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

Agora você pode passar isso para o seu controlador:

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

Uma desvantagem é que os nomes das chaves também são configurados automaticamente, o que pode dificultar a limpeza. Espero que eles adicionem de alguma forma para obter nomes-chave.

James Skemp
fonte
7

Confira o cache angular da biblioteca se você gosta do cache interno do $ http, mas deseja mais controle. Você pode usá-lo para aumentar perfeitamente o cache $ http com limpezas periódicas de tempo de vida e a opção de persistir o cache no localStorage para que ele fique disponível em todas as sessões.

FWIW, ele também fornece ferramentas e padrões para transformar seu cache em um tipo de armazenamento de dados mais dinâmico com o qual você pode interagir como POJO, em vez de apenas nas seqüências JSON padrão. Ainda não posso comentar sobre a utilidade dessa opção.

(Além disso, os dados angulares da biblioteca relacionada substituem o $ resource e / ou Restangular e dependem do cache angular.)

XML
fonte
3
Observe que angular-dataestá obsoleto agora. O mais recente é sobre js-data-angular js-data.io/v1.8.0/docs/js-data-angular
demisx
A biblioteca de cache angular possui os recursos que deveriam ter sido criados no $ cacheFactory do Angular. A solução interna parece quase inútil, devido às limitações em poder expirar caches específicos. A fábrica de cache angular também foi uma das bibliotecas de terceiros mais fáceis de implementar.
Darryl
5

Como as fábricas do AngularJS são singletons , você pode simplesmente armazenar o resultado da solicitação http e recuperá-lo na próxima vez que seu serviço for injetado em algo.

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
fonte
Eu tenho uma pergunta como verificar se GET falhou e, nesse caso, para não colocar em cache $ resource ... query ()
robert
@robert, você pode verificar o segundo argumento do método .then ou, melhor ainda, usar o retorno de chamada .catch. Por exemplo, $ http .get (url) .then (successCallback, failCallback) ou $ http .get (url) .then (successCallback, failCallback) .catch (errorCallback) O retorno de chamada de erro será executado mesmo se algo ruim acontecer no failCallback , embora seja mais comum evitar o retorno de chamada com falha e usar .then (success) .catch (manageRequestFail). Espero que ajude a entender a idéia, mais informações na documentação angular de $ 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}
        });
    }]);

defina o cache como verdadeiro.

Howardyan
fonte
Isso seria tão seguro quanto o aplicativo cliente dentro do próprio navegador, como qualquer outro aplicativo da web.
precisa saber é
-1

No Angular 8, podemos fazer assim:

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

Você pode chamar assim:

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


});

O código acima armazenará em cache o resultado da API remota na primeira chamada, para que possa ser usada em solicitações adicionais para esse método.

Raghav
fonte