【问题标题】:Right way to disable/remove http interceptors in Angular?在Angular中禁用/删除http拦截器的正确方法?
【发布时间】:2014-02-13 03:27:03
【问题描述】:

我按照这篇文章在一个项目上实现了一个类似的 ajax 加载器图像:

我的实现有一些不同:

  • 我使用$rootScopeemit 而不是broadcast,我还在指令上使用$rootScope 来处理事件。
  • 由于项目的特殊性,我必须在事件处理程序内的第一个事件被触发(显示或隐藏)后立即取消绑定指令 $rootScope.$on 侦听器。
  • 我只触发一个显示/隐藏事件。在第一个 HTTP 请求时显示,当计数达到 0 时隐藏。

我相信这些是与链接帖子的主要区别,不确定它们是否与我的问题相关,但以防万一......

当加载器隐藏事件被处理时,加载器消失了,除非页面被刷新,否则我不会再次显示它,但是我仍然有后台http请求刷新当前页面上的数据。这些请求仍将被拦截并触发不再需要/处理的新显示/隐藏事件。我只需要第一次表演和第一次隐藏,就是这样。

在第一次隐藏事件触发后,删除我添加到 $httpProvider 的 HTTP 拦截器的正确方法是什么?

我知道我们使用 $httpProvider.interceptors.push() 添加拦截器,但我不知道当我不再需要该拦截器时如何将其弹出。

【问题讨论】:

  • 在配置阶段之后,您有没有找到任何方法来获取对$httpProvider.intercerceptors 的引用?
  • 在配置阶段之后您无法获得提供者,这是不可能的。
  • 老鼠。谢谢,感谢您的快速响应

标签: angularjs angular-http-interceptors


【解决方案1】:

我找到的最佳解决方案是 jedd.ahyoung 在his comment 中解释的解决方案。

这些是步骤。

添加两个自定义工厂

angular.module('myModule.services', [])
/**
 * Save application information.
 */
.factory('Application', function($log) {
    return {};
})

/**
 * Custom Http Interceptor for the loader.
 */
.factory('myHttpInterceptor', function($rootScope, $q, Application) {
    return {
          request: function(config) {
            if(Application.enableLoader){
                $rootScope.$broadcast('loading:show');
            }
            return config;
          },

          requestError: function(rejection) {
              $rootScope.$broadcast('loading:hide');
              return $q.reject(rejection);
          },


          response: function(response) {
            $rootScope.$broadcast('loading:hide');
            return response;
          },

          responseError: function(rejection) {
              $rootScope.$broadcast('loading:hide');
              return $q.reject(rejection);
          }
    };
});

将其添加到您的 config 步骤中

.config(function($httpProvider) {
    //loading interceptor
    $httpProvider.interceptors.push('myHttpInterceptor');
});

在您想要的时间/地点启用/禁用它

Application.enableLoader = true;

$http({
  url: url,
  method: "GET"
}).success(function(data){
  $log.log("Data received and my loader is already closed :)");
  Application.enableLoader = false;
  $scope.retrieveBooks();
}).error(function(){
  $log.log("Error, but my loader is already closed :)");
  Application.enableLoader = false;
  $scope.retrieveBooks();
});


$scope.retrieveBooks = function(){
  $http({
    url: url,
    method: "GET"
  }).success(function(data){
    $log.log("Data received and my loader is not closed :(");
  }).error(function(){
    $log.log("Error, but my loader is not closed :(");
  });
};

【讨论】:

  • 虽然您的答案描述了一种让应用程序按照 OP 描述的方式运行的方法,但拦截器仍然处于活动状态,并将在每个 http 请求上调用。问题是如何从 $httpProvider 中删除它。
【解决方案2】:

我打算为此提供赏金,因为我有同样的问题。但是....根据source code$httpProvider 工厂中的第 127 和 133 行),看起来 interceptorsresponseInterceptors 只是数组。没有包装。

据我所知,您必须使用pop() 或任何其他数组方法。然而,这意味着你不知道你在弹出什么!持有对对象的引用并没有真正的帮助,因为你不能真正对它执行数组函数,除非你决定基于相等性进行迭代(这可以工作,使用 indexOf 或其他类似下划线的东西)。

真的,Angular 需要的是一个包装器,因为你不能确定你的拦截器是列表中的最后一个。

【讨论】:

  • 我在一个简单的应用程序上试过这个,我知道我的拦截器是唯一的(我还检查了数组长度)。即使我删除了我的拦截器,它仍然被调用。顺便说一句,如果您存储推送拦截器的位置的索引,您也可以使用 .slice(),这样您就不必担心弹出其他拦截器。
  • @John-Philip 是的,似乎一旦 Angular 启动后,更改配置是不行的。弹出拦截器将不起作用,因为 Angular 已经提供了服务(使用 $get),因此配置已经播种。
  • 只是一个想法。是否可以将拦截器创建为可注入的对象/函数(工厂或服务),然后为其实现某种开/关机制?
  • @LarsJuelJensen 有可能。您必须在其他地方保存对该对象的引用才能使其正常工作。使用闭包,您可以在为 $get 传递的函数中配置一个标志,如果它设置为 true,则执行 noop。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 2020-03-20
  • 1970-01-01
  • 2018-07-08
  • 2016-01-11
  • 2020-11-08
相关资源
最近更新 更多