如何使用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 拦截器阻止 HTTP 基本身份验证对话框