为Angular内置$http服务添加拦截器
在Angular框架中,创建团队为使用者进行了Ajax请求的封装,并通过$http服务暴露出相关的接口.Angular在其官方文档中指出,$http服务底层针对Web常见的安全攻击做出了相应的对策,也就是说使用$http服务封装的Ajax为使用者提供了更为安全的保障.作为一个框架,保证框架的可用性,适配性是很有必要的. Angular在设计,实现中也体现出来了这样的良好风格.我们通常在使用Ajax时,有时候希望我们能够在请求发起前或接收到请求后做一些相应的处理工作,比如:在请求发起前,在请求头中添加一下报文段.在请求返回时对一请求处理状态做一些管理,如统一处理404状态等等.Angular的$http服务在设计实现时充分考虑到了上述的情况.接下来,我们一起来学习和了解一下如何为$http服务添加拦截器,以及如何在我们自己实现的服务中实现类似的拦截器机制.
什么是拦截器–What are Interceptors?
Interceptor(拦截器)在服务端框架中属于一种比较常见的机制,如Spring,Struts2等Java框架中拦截器属于基本配置项.拦截器提供了一种机制可以使开发者可以定义在一个action(动作)执行的前后执行的代码,这些代码可以是在一个action执行前阻止其执行的代码,也可以是修改目标动作某些行为的代码.(在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。在Spring框架中比较常见)
$http服务中的拦截器
查看API或是源码我们可以发现,Angular的实现中通过
Angular中如何声明一个拦截器
// Interceptor declaration
module.factory('httpInterceptor',['$log',function($log) {
$log.debug('$log is here to show you that this is a regular factory with injection');
return {
// do something
};
}]);
如何将声明的拦截器注册到$http服务中
// Add the interceptor to $httpProvider.interceptors
module.config(['$httpProvider',function($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
}]);
通过上面的简单两个步骤,我们基本就完成了
$httpProvider暴露了那些可以拦截的点?
request : request方法可以实现拦截请求: 该方法会在
http发送请求到服务器之@H_403_1039@前执行,因此我们可以在该方法的视线中修改配置或做其他的操作。该方法接收请求配置对象(requestconfigurationobject)作为参数,然后必须返回配置对象或者promise。如果返回无效的配置对象或者promise则会被拒绝,导致 http 调用失败。response : response方法可以实现拦截响应: 该方法会在
http接收到从服务器过来的响应之后执行,因此我们可以修改响应报文或做其他操作。该方法接收响应对象(responseobject)作为参数,然后必须返回响应对象或者promise。响应对象包括了请求配置(requestco@H_735_2502@nfiguration),头(headers),状态(status)和从后台过来的数据(data)。如果返回无效的响应对象或者promise会被拒绝,导致 http 调用失败。requestError : requestError方法可以实现拦截请求异常: 有时候一个请求发送失败或者被拦截器拒绝了。请求异常拦截器会俘获那些被上一个请求拦截器中断的请求。它可以用来恢复请求或者有时可以用来撤销请求之前所做的配置,比如说关闭进度条,激活按钮和输入框什么之类的。
responseError : responseError方法可以实现拦截响应异常: 有时候我们后台调用失败了。也有可能它被一个请求拦截器拒绝了,或者被上一个响应拦截器中断了。在这种情况下,响应异常拦截器可以帮助我们恢复后台调用。
对于上面暴露出来的接口使用也是异常的简单的,我们可以像声明一个简单的服务一样声明一个$http服务的拦截器,并交由angular的注入机制去使用我们配置的拦截器.
// 如同声明一个Angular服务一样声明一个拦截器
module.factory('sessionInjector',['authService',function (authService){
return {
request: function (config){
if (!authService.isAnonymus) {
config.headers['x-session-token'] = authService.token;
}
return config;
}
};
}]);
// 然后将我们声明的拦截器添加到$httpProvider的拦截器链中,之后的服务注入Angular会负责帮我们完善
module.config(['$httpProvider',function ($httpProvider){
$httpProvider.interceptors.push('sessionInjector');
}]);
$http服务拦截器的异步支持
部分场景下,我们希望在拦截器中能够执行一些异步操作.然后依据不同的处理结果进行不同的拦截操作,AngularJS在设计的时候也很好的支持了这一特性.AngularJS允许我们在拦截的方法中,我们可以返回一个promise对象.如在@H_404_2972@
module.factory('myInterceptor',['$q','someAsyncService',function($q,someAsyncService) {
var requestInterceptor = {
request: function(config) {
var deferred = $q.defer();
someAsyncService.doAsyncOperation().then(function() {
// Asynchronous operation succeeded,modify config accordingly
...
deferred.resolve(config);
},function() {
// Asynchronous operation Failed,modify config accordingly
...
deferred.resolve(config);
});
return deferred.promise;
},response: function(response) {
var deferred = $q.defer();
someAsyncService.doAsyncOperation().then(function() {
// Asynchronous operation succeeded,modify response accordingly
...
deferred.resolve(response);
},function() {
// Asynchronous operation Failed,modify response accordingly
...
deferred.resolve(response);
});
return deferred.promise;
}
};
return requestInterceptor;
}]);
上面的例子中,在请求发起时,如果对应的deferred被拒绝,http请求则会失败(如果进行抓包分析的话,你会发现http请求并没有发起).在请求进行响应时,如果deferred被拒绝,则请求也会失败.(抓包分析,网络请求是有返回的).
– 之后会介绍如何在自己的声明的服务中实现拦截器(如果比较着急或是感兴趣的朋友可以去阅读$httpProvider的源码)