Angularjs 拦截某些路线最干净的方法是什么?

Angularjs 拦截某些路线最干净的方法是什么?,angularjs,Angularjs,我正在使用拦截器,它们拦截所有请求,但我有一些不想干扰请求/响应的路由 app.service('WizardService', ['$http', function($http) { var base_url = '/api'; var service = {}; service.postStep1 = function (){ return $http.post(base_url+'/step-1'); }; service.p

我正在使用拦截器,它们拦截所有请求,但我有一些不想干扰请求/响应的路由

app.service('WizardService', ['$http', function($http) {

    var base_url = '/api';
    var service = {};

    service.postStep1 = function (){

       return $http.post(base_url+'/step-1');

    };

    service.postStep2 = function (data){

       return $http.post(base_url+'/step-2', data);

    };

    service.postStep3 = function (data){

       return $http.post(base_url+'/step-3', data);

    };

    return service;

}]);

对于第1步和第2步,我想使用InteceptorA,第3步我想使用InterceptorB。最干净的方法是什么?

实现一个拦截器,如中所示

如果需要拦截请求,请在
'requests'
回调中检查
config.url
并使用类似regex匹配的内容。例如:

// register the interceptor as a service
$provide.factory('myInterceptor', function() {
  return {
    'request': function(config) {
      if (/step-1$/.test(config.url)) doSomething1();
      if (/step-2$/.test(config.url)) doSomething2();
      if (/step-3$/.test(config.url)) doSomething3();
      return config;
    }
  }
}  

丁香回答的是好的,但如果有多条路线,则很难根据URL分配多个
if
条件。此外,如果URL发生更改,还需要在拦截器中进行修改

我想实现这一点最干净的方法是配置。让我们从您的服务开始:

app.service('WizardService', ['$http', function($http) {

    var base_url = '/api';
    var service = {};

    service.postStep1 = function (){
       return $http.post(base_url + '/step-3', null, {interceptMe: 'A'});
    };

    service.postStep2 = function (data){
       return $http.post(base_url + '/step-2', null, {interceptMe: 'A'});
    };

    service.postStep3 = function (data){
       return $http.post(base_url + '/step-3', null, {interceptMe: 'B'});
    };

    service.postStep4 = function (data) {
       // no interception
       return $http.post(base_url + '/step-3');
    };

    return service;
}]);
现在,注册拦截器(我只是向您展示拦截器的主要逻辑):


首先,
$http
服务及其使用的
$httpProvider.interceptors
属性中没有任何内容可以帮助您完成所需的任务

.interceptors
是一个平面阵列(第375行):

他们最终只是被推(或取消)到承诺链中,这取决于是请求还是响应

第986行:

// apply interceptors
forEach(reversedInterceptors, function(interceptor) {
    if (interceptor.request || interceptor.requestError) {
      chain.unshift(interceptor.request, interceptor.requestError);
    }
    if (interceptor.response || interceptor.responseError) {
      chain.push(interceptor.response, interceptor.responseError);
    }
});
因此,除了滚动您自己的
$http
服务的替代方案(在本例中我不建议这样做),您还必须在http拦截器本身的范围内工作。换句话说,拦截器必须自己管理过滤路由

我认为有3种稍微不同的方法可以解决这个问题

  • 单个拦截器充当“封送器”,根据路由调用逻辑
  • 多个拦截器,每个拦截器都有自己的路由过滤逻辑
  • 具有配置/注入路由过滤逻辑的多个拦截器
  • 以下哪种方法最适合您将取决于以下几个因素:

    • 拦截器数量
    • 路由筛选的复杂性(您的示例可能是一个简化的示例)
    • 过滤规则独立于拦截器逻辑更改的可能性
    关于单身人士的说明

    请记住,服务是单件的。它们只创建一次,然后重复使用。Per:

    依赖于服务的每个组件都会获得对服务工厂生成的单个实例的引用

    因此,如果注册了多个拦截器,那么
    $http
    在经历一个长的承诺链时无疑会有一些开销,但这并不像最初看起来的那样费力。也就是说,您在评论中提到,您可能会注册多达100个拦截器,我无法评论可能会或可能不会产生的具体性能影响

    1-单拦截器 丁香回答已经为这一点提供了一个例子,沙尚克的答案也是如此。大概是这样的:

    function SingleInterceptor() {
        var service = {
            request: request
        };
    
        return service;
    
        function request(config) {
            if (config.url === base_url + '/step-1') {
                step1Logic();
            }
            if (config.url === base_url + '/step-2') {
                step2Logic();
            }
            // etc...
            return config;
        }
    }
    
    如果您没有太多不同的拦截器逻辑需要处理,那么这是非常简洁的,但是在更高的卷中维护可能会变得有点笨拙

    2-多个拦截器(具有自己的过滤) 每个拦截器都有自己的逻辑来确定路由是否适用。比如:

    function InterceptorStep1() {
        var service = {
            request: request
        };
    
        return service;
    
        function request(config) {
            if (config.url === base_url + '/step-1') {
                // Step 1 logic here
            }
            return config;
        }
    }
    
    function InterceptorStep1() {
        var service = {
            request: request
        };
    
        return service;
    
        function request(config) {
            if (config.url === base_url + '/step-2') {
                // Step 2 logic here
            }
            return config;
        }
    }
    
    这在大容量情况下更易于维护,但如果您想开始更改过滤规则,或者拦截器没有明显的URL一对一映射,则会变得很尴尬。在这里假设,也许它们并不像“第一步”、“第二步”那么明显

    3-多个拦截器(基于配置的过滤) 与#2类似,但通过为每个拦截器使用一个提供程序,将路由过滤逻辑与拦截器本身分开

    function InterceptorB(filterUrl) {
        var service = {
            request: request
        };
    
        return service;
    
        function request(config) {
            if (!filterUrl || filterUrl(config.url)) {
                // Logic here
            }
            return config;
        }
    }
    
    angular
        .module('app')
        .provider('InterceptorB', function InterceptorBProvider() {
            var filterUrlInner;
    
            this.setFilterUrlCallback = function (fn) {
                filterUrlInner = fn;
            };
    
            this.$get = [function InterceptorBFactory($log) {
                return new InterceptorB(filterUrlInner);
            }];
        });
    

    首先,设置此拦截器需要做更多的工作,但在我看来,如果您拥有的拦截器不止几个,那么它将是最灵活、最容易维护的拦截器。

    有什么理由支持使用此拦截器而不是使用多个拦截器?首先,谢谢。但是如果我有100条路线,这就没有意义了。如何使用各种拦截器并将它们分配到特定的路由?
    function InterceptorStep1() {
        var service = {
            request: request
        };
    
        return service;
    
        function request(config) {
            if (config.url === base_url + '/step-1') {
                // Step 1 logic here
            }
            return config;
        }
    }
    
    function InterceptorStep1() {
        var service = {
            request: request
        };
    
        return service;
    
        function request(config) {
            if (config.url === base_url + '/step-2') {
                // Step 2 logic here
            }
            return config;
        }
    }
    
    function InterceptorB(filterUrl) {
        var service = {
            request: request
        };
    
        return service;
    
        function request(config) {
            if (!filterUrl || filterUrl(config.url)) {
                // Logic here
            }
            return config;
        }
    }
    
    angular
        .module('app')
        .provider('InterceptorB', function InterceptorBProvider() {
            var filterUrlInner;
    
            this.setFilterUrlCallback = function (fn) {
                filterUrlInner = fn;
            };
    
            this.$get = [function InterceptorBFactory($log) {
                return new InterceptorB(filterUrlInner);
            }];
        });