【问题标题】:Invalidate $resource Cache After Post Request发布请求后使 $resource 缓存无效
【发布时间】:2014-09-26 20:24:47
【问题描述】:

我正在使用 $resource 并缓存 get 请求的结果。我的问题是,在发布请求后,缓存没有失效。

这是服务的返回值:

return $resource('http://url.com/api/url/:id', {}, {
'query' : {
      method : 'GET',
      isArray:true,
      cache : true
    },
'get' : {
  method : 'GET',
  cache : false
}  
})

这是我在控制器中使用的保存方法。如您所见,我正在使用 post 请求上的回调来重新计算查询/名词列表。

var newNoun = new Noun($scope.noun);
newNoun.$save(function(x) {
  $scope.nouns = Noun.query();
});

我想在调用 post 或其他非 get 方法后使缓存无效。我怎么能这样做?这是否已经内置在 $resource 中,还是我需要自己实现?

【问题讨论】:

  • 我在研究如何做到这一点时遇到了这个问题。问题是我不知道如何将代码集成到服务/控制器方法中。我尝试了几种方法,但无法正常工作。请问你能告诉我你会怎么做吗?
  • 您想仅对每个资源 ID 或整个缓存进行无效缓存吗?
  • 我希望它能够反映发出的请求。例如,如果我向 /nouns 发帖,它应该使对 /nouns 的获取请求无效。如果我发布到 /nouns/5,它应该使缓存中的 /nouns/5 的获取请求无效。

标签: angularjs angularjs-resource


【解决方案1】:

$resource 正在使用$http 的默认缓存。

您可以使用以下方式访问它:$cacheFactory.get('$http')

您可以使用返回的缓存remove({string} key) 方法删除键值对。


例如:

var key = '...the key you want to remove, e.g. `/nouns/5`...';
$cacheFactory.get('$http').remove(key);

【讨论】:

  • 感谢您的回答。有没有一种好方法可以将其集成到服务中,以便自动完成?还是每次使用都需要在回调中实现?
【解决方案2】:

虽然@runTarm 的上述回答很棒,但它不允许从继承服务轻松自定义操作,例如以下是不可能的:

app.factory('Steps', function (CachedResource) {
    return CachedResource('/steps/:stepId', {}, {
        save: { method: 'POST', params: { stepId: '@stepId' } }
    });
});

在这种情况下,save 的定义将被 CachedResource 中的定义替换。

解决方案

但它可以通过替换

Angular 1.4 轻松修复
actions = angular.extend({}, actions, {

actions = angular.merge({}, actions, {

这样两个对象都被深度合并了。

更好的解决方案

在上述场景中,在 CachedResource 中定义的操作选项将优先于继承服务中的自定义配置。要解决此问题,请将传递给 merge 的参数顺序切换:

actions = angular.merge({}, { /* default options get, query, etc. */ }, actions);

使用此解决方案,以下将按预期工作(即在调用 remove 时使用 DESTROY 而不是默认的 DELETE):

app.factory('Steps', function (CachedResource) {
    return CachedResource('/steps/:stepId', {}, {
        remove: { method: 'DESTROY' }
    });
}); 

【讨论】:

  • 使用这个方法,你会如何添加一个update 方法,它仍然使缓存项无效?我认为您必须以某种方式公开拦截器才能做到这一点。
【解决方案3】:

你可以创建一个包装服务来做你想要的缓存,例如:

app.factory('cachedResource', function ($resource, $cacheFactory) {
  var cache = $cacheFactory('resourceCache');

  var interceptor = {
    response: function (response) {
      cache.remove(response.config.url);
      console.log('cache removed', response.config.url);
      return response;
    }
  };

  return function (url, paramDefaults, actions, options) {
    actions = angular.extend({}, actions, {
      'get':    { method: 'GET', cache: cache },
      'query':  { method: 'GET', cache: cache, isArray: true },
      'save':   { method: 'POST', interceptor: interceptor },
      'remove': { method: 'DELETE', interceptor: interceptor },
      'delete': { method: 'DELETE', interceptor: interceptor },
    });

    return $resource(url, paramDefaults, actions, options);
  };
});

然后将任何$resource 替换为cachedResource

示例插件: http://plnkr.co/edit/lIQw4uogcoMpcuHTWy2U?p=preview

【讨论】:

  • +1 太棒了!奇迹般有效。我会尽可能将'update': {method: 'PUT', interceptor: interceptor} 添加到操作列表中。 (我不得不将 +1 放在 code 中,因为显然它会分散你对我第二句话的注意力......wtf)
  • 我认为拦截器还应该删除查询 URL 的条目,否则查询会在您保存/删除/删除条目后返回旧信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-10
  • 2018-11-04
  • 1970-01-01
  • 2013-06-08
相关资源
最近更新 更多