详解为Angular.js内置$http服务添加拦截器的方法


Posted in Javascript onDecember 20, 2016

前言

在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的实现中通过 httpProvider提供了一个名为interceptors的数组.这个数组接受拦截器服务注册,通过过程次的注册最终会形成拦截器链.这样每次在调用http服务的时候,angular都会通过我们定义的拦截点(切面)进行相应的Ajax动作修改.理论就不多说了,下面开始进入实战:

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');
}]);

通过上面的简单两个步骤,我们基本就完成了http服务的拦截器编写与添加.但是上面的代码片段并不能实际使用,要想真正的实现拦截操作,我们还需要遵循http服务暴露出来的可以进行拦截的点进行相关的代码编写.

$httpProvider暴露了那些可以拦截的点?

  1. request : request方法可以实现拦截请求: 该方法会在 http发送请求到服务器之前执行,因此我们可以在该方法的视线中修改配置或做其他的操作。该方法接收请求配置对象(requestconfigurationobject)作为参数,然后必须返回配置对象或者promise。如果返回无效的配置对象或者promise则会被拒绝,导致http 调用失败。
  2. response : response方法可以实现拦截响应: 该方法会在 http接收到从服务器过来的响应之后执行,因此我们可以修改响应报文或做其他操作。该方法接收响应对象(responseobject)作为参数,然后必须返回响应对象或者promise。响应对象包括了请求配置(requestconfiguration),头(headers),状态(status)和从后台过来的数据(data)。如果返回无效的响应对象或者promise会被拒绝,导致http 调用失败。
  3. requestError : requestError方法可以实现拦截请求异常: 有时候一个请求发送失败或者被拦截器拒绝了。请求异常拦截器会俘获那些被上一个请求拦截器中断的请求。它可以用来恢复请求或者有时可以用来撤销请求之前所做的配置,比如说关闭进度条,激活按钮和输入框什么之类的。
  4. 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对象.如在http服务中,我们如果返回一个promise对象时,http服务将会延迟发起网络请求或是延迟响应请求结果.

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被拒绝,则请求也会失败.(抓包分析,网络请求是有返回的).

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Javascript 相关文章推荐
使用JQuery进行跨域请求
Jan 25 Javascript
JQuery select控件的相关操作实现代码
Sep 14 Javascript
JQuery操作iframe父页面与子页面的元素与方法(实例讲解)
Nov 20 Javascript
JSON与XML优缺点对比分析
Jul 17 Javascript
利用JS实现页面删除并重新排序功能
Dec 09 Javascript
从零开始学习Node.js系列教程之SQLite3和MongoDB用法分析
Apr 13 Javascript
微信JS-SDK选取手机照片上传功能
Apr 21 Javascript
angularJs中跳转到指定的锚点实例($anchorScroll)
Aug 31 Javascript
JS实现的贪吃蛇游戏完整实例
Jan 18 Javascript
Vue项目中配置pug解析支持
May 10 Javascript
详解wepy开发小程序踩过的坑(小结)
May 22 Javascript
Vue关于组件化开发知识点详解
May 13 Javascript
[Bootstrap-插件使用]Jcrop+fileinput组合实现头像上传功能实例代码
Dec 20 #Javascript
JS简单实现表格排序功能示例
Dec 20 #Javascript
深入了解JavaScript的逻辑运算符(与、或)
Dec 20 #Javascript
js定时器实例分享
Dec 20 #Javascript
BootStrap Table 获取同行不同列元素的方法
Dec 19 #Javascript
Jquery Easyui进度条组件Progress使用详解(8)
Mar 26 #Javascript
详解Jquery的事件操作和文档操作
Dec 19 #Javascript
You might like
PHP新手NOTICE错误常见解决方法
2011/12/07 PHP
destoon整合UCenter图文教程
2014/06/21 PHP
Laravel框架实现的记录SQL日志功能示例
2018/06/19 PHP
jQuery LigerUI 插件介绍及使用之ligerDrag和ligerResizable示例代码打包
2011/04/06 Javascript
javascript (用setTimeout而非setInterval)
2011/12/28 Javascript
JS获取html对象的几种方式介绍
2013/12/05 Javascript
jQuery使用元素属性attr赋值详解
2015/02/27 Javascript
jQuery实现监控页面所有ajax请求的方法
2015/12/10 Javascript
表单input项使用label同时引用Bootstrap库导致input点击效果区增大问题
2016/10/11 Javascript
深入理解vue.js双向绑定的实现原理
2016/12/05 Javascript
js判断手机号是否正确并返回的实现代码
2017/01/17 Javascript
JavaScript中在光标处插入添加文本标签节点的详细方法
2017/03/22 Javascript
easyui关于validatebox实现多重规则验证的方法(必看)
2017/04/12 Javascript
angular ng-click防止重复提交实例
2017/06/16 Javascript
vue-resource请求实现http登录拦截或者路由拦截的方法
2018/07/11 Javascript
jQuery层叠选择器用法实例分析
2019/06/28 jQuery
JavaScript隐式类型转换代码实例
2020/05/29 Javascript
jquery轮播图插件使用方法详解
2020/07/31 jQuery
python实现简单的TCP代理服务器
2014/10/08 Python
Python计算三角函数之asin()方法的使用
2015/05/15 Python
Python 爬取携程所有机票的实例代码
2018/06/11 Python
python实现嵌套列表平铺的两种方法
2018/11/08 Python
Python 中PyQt5 点击主窗口弹出另一个窗口的实现方法
2019/07/04 Python
python2爬取百度贴吧指定关键字和图片代码实例
2019/08/14 Python
css3 2D图片转动样式可以扩充到Js当中
2014/04/29 HTML / CSS
Exoticca英国:以最优惠的价格提供豪华异国情调旅行
2018/10/18 全球购物
测控技术自荐信
2014/06/05 职场文书
护士优质服务演讲稿
2014/08/26 职场文书
离婚协议书范本(通用篇)
2014/11/30 职场文书
店长岗位职责
2015/02/11 职场文书
优秀团员个人总结
2015/02/26 职场文书
物业工程部主管岗位职责
2015/04/16 职场文书
英文投诉信格式
2015/07/03 职场文书
日本官方排名前10的动漫,名侦探柯南上榜,第一是一部创造历史的动漫
2022/03/18 日漫
Python使用MapReduce进行简单的销售统计
2022/04/22 Python
排查Tomcat进程假死的问题
2022/05/06 Servers