如何使用angularJS拦截器只拦截特定的http请求?

Posted

技术标签:

【中文标题】如何使用angularJS拦截器只拦截特定的http请求?【英文标题】:How to use angularJS interceptor to only intercept specific http requests? 【发布时间】: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);
      
    ;
  );

【问题讨论】:

【参考方案1】:

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

例如

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

    return response;

...

用于 string.startsWith() 的 Polyfill

//Taken from http://***.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);
                
            
        ;
    ]);

【讨论】:

以上是关于如何使用angularJS拦截器只拦截特定的http请求?的主要内容,如果未能解决你的问题,请参考以下文章

关于angularJs的拦截器的使用

使用 AngularJS 拦截器阻止 HTTP 基本身份验证对话框

angularjs拦截器:为啥在$http拦截器中没有收到正确的状态码和消息

burpsuite只拦截特定网站数据包教程

如何拦截特定请求

Angularjs注入拦截器实现Loading效果