【问题标题】:Cache an HTTP 'Get' service response in AngularJS?在 AngularJS 中缓存 HTTP 'Get' 服务响应?
【发布时间】:2012-12-16 13:27:18
【问题描述】:

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

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

这可能吗?

【问题讨论】:

    标签: angularjs ajax caching http-get


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

    【讨论】:

    • 这个问题与 AngularJS 而不是 Angular 有关,它们是完全不同的框架
    【解决方案2】:

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

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

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

    【讨论】:

    • 请注意,angular-data 现在已弃用。最新的是js-data-angularjs-data.io/v1.8.0/docs/js-data-angular
    • angular-cache 库具有应该内置到 Angular 的 $cacheFactory 中的功能。内置解决方案似乎几乎没用,因为它在使特定缓存过期方面存在限制。角度缓存工厂也是最容易实现的第 3 方库之一。
    【解决方案3】:

    Angular 的$http 有一个cache built in。根据文档:

    cache – {boolean|Object} – 使用 $cacheFactory 创建的布尔值或对象,用于启用或禁用 HTTP 响应的缓存。看 $http Caching for more information.

    布尔值

    因此您可以在其选项中将cache 设置为true

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

    【讨论】:

    • 问题:将缓存数据保存到 $cacheFactory 有什么意义。为什么不直接将其保存到服务中的本地对象中?有什么好的理由吗?
    • 看看这个。它为您提供了许多可定制性,包括本地存储支持、超时支持、各种好东西http://jmdobry.github.io/angular-cache/
    • 我对状态码 304 特别好奇——浏览器缓存是否可以在不启用缓存的情况下工作:true?如果没有,是否 cache:true 使它工作?缓存是永久的还是只是在 RAM 中并在页面关闭时被卸载?
    • 有什么方法可以在不手动实现的情况下指定这个缓存的时间限制?
    • @Spock,$cacheFactory 本身就是一项可以跨多个控制器和角度组件使用的服务。它可以用作通用 api 服务,将所有 $http 缓存到单个服务 obj 中,而不是为每个服务对象设置不同的服务对象。
    【解决方案4】:
    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}
            });
        }]);
    

    设置缓存为真。

    【讨论】:

    • 这将与带有浏览器本身的客户端应用程序一样安全,就像任何其他 Web 应用程序一样。
    【解决方案5】:

    由于 AngularJS 工厂是 singletons,因此您可以简单地存储 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 文档中的更多信息。
    【解决方案6】:

    在当前稳定版本 (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 请求($resource 继承)启用基本缓存:

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

      【讨论】:

      • 你几乎不想缓存每一个 http 请求。我不知道什么时候会出现这种情况?
      • 每个应用程序/模块都是不同的,不是吗?!
      • 如果你想缓存大部分请求,那么将默认值设置为 true 会很方便。
      猜你喜欢
      • 1970-01-01
      • 2020-01-16
      • 1970-01-01
      • 2011-03-25
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 1970-01-01
      • 2017-11-24
      相关资源
      最近更新 更多