【问题标题】:How to use angularJS interceptor to only intercept specific http requests?如何使用angularJS拦截器只拦截特定的http请求?
【发布时间】:2014-05-26 03:07:09
【问题描述】:

我知道如何拦截所有请求,但我只想拦截来自我的资源的请求。

有人知道怎么做吗?

services.config(['$httpProvider',function($httpProvider) {
    $httpProvider.interceptors.push('myHttpInterceptor');
}]);

services.factory("userPurchased", function ($resource) {
    return $resource("/api/user/purchases/:action/:item", 
        {}, 
        {
            'list': {method: 'GET', params: {action: 'list'}, isArray: false},
            'save': {method: 'PUT', params: {item: '@item'}},
            'remove': {method: 'DELETE', params: {item: '@item'}},
        }
    );
});

services.factory('myHttpInterceptor', function($q,$rootScope) {
    // $rootScope.showSpinner = false;
    return {

      response: function(response) {
        $rootScope.showSpinner = false;
        // do something on success
        console.log('success');
        console.log('status', response.status);
        //return response;
        return response || $q.when(response);
      },

     responseError: function(response) {
        // do something on error
        $rootScope.showSpinner = true;
        console.log('failure');
        console.log('status', response.status)
        //return response;
        return $q.reject(response);
      }
    };
  });

【问题讨论】:

    标签: angularjs angularjs-service


    【解决方案1】:

    我知道这样做的唯一方法是在响应处理程序中过滤掉您想要的请求。

    例如

    ...
    response: function(response) {
        if(response.config.url.startsWith('/api/')) {
            //Do your custom processing here
        }
    
        return response;
    }
    ...
    

    用于 string.startsWith() 的 Polyfill

    //Taken from http://stackoverflow.com/questions/646628/javascript-startswith
    if (typeof(String.prototype.startsWith) === 'undefined') {
        String.prototype.startsWith = function(str) {
            return this.slice(0, str.length) === str;
        };
    }
    

    【讨论】:

    • 如果您使用的是直接 url,旧的 indexOf('/api/') > -1 也应该可以工作
    • 此答案仅在其余 api 使用 '/api/' 正确命名的情况下才有效。我更喜欢检查 http 标头的内容类型(例如 XML 或 JSON)
    【解决方案2】:

    如果您只想拦截来自特定资源的请求,您可以使用$request 操作的可选interceptor 属性。 Angular 的文档see here (Usage>actions)

    JavaScript

    angular.module('app', ['ngResource']).
      factory('resourceInterceptor', function() {
        return {
          response: function(response) {
            console.log('response intercepted: ', response);
          }
        }
      }).
      factory('resourceService', ['$resource', 'resourceInterceptor', function($resource, resourceInterceptor) {
        return $resource(":name", 
            {}, 
            {
                'list': {method: 'GET', isArray: false, interceptor: resourceInterceptor}
            }
        );
      }]).
      run(['resourceService', '$http', function(resourceService, $http) {
        resourceService.list({name: 'list.json'}); // <= intercepted
        $http.get('list.json'); // <= not intercepted
      }]);
    

    Plunker:http://plnkr.co/edit/xjJH1rdJyB6vvpDACJOT?p=preview

    【讨论】:

    • 谢谢 - 这正是我想要的!
    • 正是我需要的!谢谢!
    • 当我将多个拦截器推送到 httpProvider 时,这不起作用。我只想调用一个特定的拦截器,我正在做如上所述的事情,但是我注册的所有拦截器都会调用请求方法。
    【解决方案3】:
    /**object single interceptor**/ 
     function SingleCallInterceptor(callbacks){
    
        this.receive=function(response) {
    
          switch (response.status) {
    
            case 200:
    
              callbacks.success(apiResponse);
    
              break;
    
            default :
    
              callbacks.error(response);
          }
    
        }
    
      }
    
    
    var successfn=function(response){  //i have my response}
    
    var errorfn=function(response){  //i have my error}
    
    var responseInterceptor=new SingleCallInterceptor({success:successfn,error:errorfn});
    
            $http({
    
            url: "www.itsdirtysolutioniknow.it,
    
            method: "GET",
    
            dataType: "JSONP",
    
          }).then(responseInterceptor.receive,responseInterceptor.receive);
    

    【讨论】:

    • 这只是提供一个回调函数。如何将它用作 http 调用拦截器?
    【解决方案4】:

    我的首选方法是使用 HTTP 拦截器,它将“神奇”授权标头替换为当前 OAuth 令牌。下面的代码是特定于 OAuth 的,但对读者来说是一个简单的练习。

    // Injects an HTTP interceptor that replaces a "Bearer" authorization header
    // with the current Bearer token.
    module.factory('oauthHttpInterceptor', function (OAuth) {
      return {
        request: function (config) {
          if (config.headers.Authorization === 'Bearer') {
            config.headers.Authorization = 'Bearer ' + btoa(OAuth.accessToken);
          }
          return config;
        }
      };
    });
    
    module.config(function ($httpProvider) {
      $httpProvider.interceptors.push('oauthHttpInterceptor');
    });
    

    【讨论】:

    • 这并不能真正回答所提出的问题
    • 确实如此 - 只需为您的请求(而不是其他请求)提供“承载”/“魔术字符串”的 Authorization 标头,然后将调用拦截器。你可以使用公认的答案——这可能更明显——但这意味着你在任何地方都绑定了那个拦截器——而我的例子中的方法提供了间接性。
    【解决方案5】:

    默认情况下,Angular 发送和接收 application/json 标头。您可以在 HTTP 响应标头上获取此信息,例如:

    services.config(['$httpProvider',function($httpProvider) {
        $httpProvider.interceptors.push('myHttpInterceptor');
    }]);
    
    services.factory("userPurchased", function ($resource) {
        return $resource("/api/user/purchases/:action/:item", 
            {}, 
            {
                'list': {method: 'GET', params: {action: 'list'}, isArray: false},
                'save': {method: 'PUT', params: {item: '@item'}},
                'remove': {method: 'DELETE', params: {item: '@item'}},
            }
        );
    });
    
    services.factory('myHttpInterceptor', function($q,$rootScope) {
        // $rootScope.showSpinner = false;
        return {
    
          response: function(response) {
            // use this line to if you are receiving json, else use xml or any other type
            var isJson = response.config.headers.Accept.indexOf('json')>-1;
            $rootScope.showSpinner = false;
            // do something on success
            console.log('success');
            console.log('status', response.status);
            //return response;
            return response || $q.when(response);
          },
    
         responseError: function(response) {
            // use this line to if you are receiving json, else use xml or any other type
            var isJson = response.config.headers.Accept.indexOf('json')>-1;
            // do something on error
            $rootScope.showSpinner = true;
            console.log('failure');
            console.log('status', response.status)
            //return response;
            return $q.reject(response);
          }
        };
      });
    

    【讨论】:

      【解决方案6】:

      我刚刚遇到了一个问题,其中 googleapis 也使用 Authorization 标头,并抛出 401 响应,因为我在服务器上使用的 JWT 对他们的服务器无效(显然),并且我的代码设置为自动删除我的令牌并将此人重定向到登录页面。 (写得不是很好,因为任何 401 响应都会让我的用户退出)。

      我刚刚在拦截器中的request 方法中提出了这个解决方案,我认为它效果很好:

      .service('authInterceptor', ["$q", "$location", "tokenService", function($q, $location, tokenService){
          this.request = function(config) {
      //        console.log($location.host());
              var token = tokenService.getToken();
              if(token && config.url.indexOf($location.host()) > -1) {
                  config.headers = config.headers || {};
                  config.headers.Authorization = "Bearer " + token
              }
              return config
          }
      
          this.responseError = function(response) {
      //        console.log(response.config.url)
              if (response.status === 401) {
                  tokenService.removeToken();
                  $location.path('/login')
              }
              return $q.reject(response);
          }
      }])
      

      request 方法检查我在本地存储中是否有令牌 AND 请求 URL 是否发送到与我的页面相同的主机(我从 $location.host() 获得)正在上菜。这适用于 localhost 以及我最终在其上部署网站的任何 URL。

      我没有对此进行太多测试,所以如果有人发现其中的缺陷,请告诉我:)

      【讨论】:

        【解决方案7】:

        我知道这是一个老问题,但如果您推送了多个 $http 拦截器并希望它们继续工作,我想提供一个解决方案,返回您的响应以便拦截器链继续:

            module.factory('resourceInterceptor', ['$q', function($q) {
                return {
                    response: function(response) {
                        // do your conditional logic here
                        if (...) {
                            return $q.resolve(response);
                        }
                    },
                    responseError: function(response) {
                        // do your conditional logic here   
                        if (...) {
                            return $q.reject(response);
                        }
                    }
                };
            }]);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-10-05
          • 2020-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多