在AngularJS中缓存HTTP“获取”服务响应?


211

我希望能够创建一个自定义AngularJS服务,当其数据对象为空时发出HTTP“获取”请求,并在成功时填充该数据对象。

下次调用此服务时,我想绕过再次发出HTTP请求的开销,而是返回缓存的数据对象。

这可能吗?

Answers:


315

Angular的$ http 内置了一个缓存。根据文档:

cache – {boolean | Object} – 用$ cacheFactory创建的布尔值或对象,用于启用或禁用HTTP响应的缓存。有关更多信息,请参见 $ http缓存

布尔值

因此,您可以在其选项中将其设置cachetrue

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

或者,如果您更喜欢呼叫的配置类型:

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

快取物件

您还可以使用缓存工厂:

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

47
问题:将缓存的数据保存到$ cacheFactory ..为什么不将其保存到Service的本地对象中呢?有什么好的理由吗?
Spock 2013年

7
看一下这个。它为您提供了许多可定制性,包括localStorage支持,超时支持,各种便利产品http://jmdobry.github.io/angular-cache/
Erik Donohoo 2014年

4
我对状态代码304感到特别好奇-浏览器缓存是否在不启用cache:true的情况下工作?如果没有,cache:true是否可以正常工作?缓存是永久的还是仅在RAM中,并且在关闭页面时已卸载?
sasha.sochka,2015年

3
是否可以在不手动执行的情况下为此缓存指定时间限制?
2015年

11
@ Spock,$ cacheFactory本身是一项可以在多个控制器和角度组件之间使用的服务。它可以用作通用api服务,将所有$ http缓存到单个服务obj中,而不是为每个服务对象使用不同的服务对象。
尼拉夫·甘地

48

我认为现在有一种更简单的方法。这将为所有$ http请求($ resource继承的)启用基本缓存:

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

46
您几乎不需要缓存每个http请求。我不知道什么时候会发生这种情况?
Spock

1
每个应用程序/模块都不同,不是吗?
rodrigo-silveira 2014年

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

如果您喜欢$ http的内置缓存,但需要更多控制,请查看库angular-cache。您可以使用它通过生存时间,定期清除以及将缓存持久化到localStorage的选项来无缝地扩展$ http缓存,以便跨会话使用。

FWIW,它还提供了工具和模式,使您的缓存成为一种可以作为POJO进行交互的更具动态性的数据存储,而不仅仅是默认的JSON字符串。尚无法评论该选项的实用程序。

(然后,最重要的是,相关的库angular-data可以替代$ resource和/或Restangular,并且依赖于angular-cache。)


3
请注意,angular-data现在已弃用。最新的是js-data-angular js-data.io/v1.8.0/docs/js-data-angular
demisx

angular-cache库具有应在Angular的$ cacheFactory中内置的功能。内置解决方案似乎无济于事,因为它能够使特定的缓存失效。角度缓存工厂也是最容易实现的第三方库之一。
达里尔

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

我有一个问题,如何检查GET是否失败,并且在这种情况下不要将$ resource ... query()放入缓存中
罗伯特·罗伯特(

@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。


就像其他任何Web应用程序一样,这与带有浏览器的客户端应用程序一样安全。
bhantol '16

-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的结果,以便可以在对该方法的进一步请求中使用它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.