详解Angular.js中$http拦截器的介绍及使用


Posted in Javascript onJuly 04, 2017

前言

$http service在Angular中用于简化与后台的交互过程,其本质上使用XMLHttpRequest或JSONP进行与后台的数据交互。在与后台的交互过程中,可能会对每条请求发送到Server之前进行预处理(如加入token),或者是在Server返回数据到达客户端还未被处理之前进行预处理(如将非JSON格式数据进行转换);当然还有可能对在请求和响应过程过发生的问题进行捕获处理。所有这些需求在开发中都非常常见,所以Angular为我们提供了$http拦截器,用来实现上述需求。

什么是拦截器

顾名思义,拦截器就是在目标达到目的地之前对其进行处理以便处理结果更加符合我们的预期。Angular的$http拦截器是通过$httpProvider.interceptors数组定义的一组拦截器,每个拦截器都是实现了某些特定方法的Factory:

详解Angular.js中$http拦截器的介绍及使用

实现拦截器

http拦截器一般通过定义factory的方式实现:

myApp.factory('MyInterceptor', function($q) {
 return {
 // 可选,拦截成功的请求
 request: function(config) {
  // 进行预处理
  // ...
  return config || $q.when(config);
 },

 // 可选,拦截失败的请求
 requestError: function(rejection) {
  // 对失败的请求进行处理
  // ...
  if (canRecover(rejection)) {
  return responseOrNewPromise
  }
  return $q.reject(rejection);
 },



 // 可选,拦截成功的响应
 response: function(response) {
  // 进行预处理
  // ....
  return response || $q.when(reponse);
 },

 // 可选,拦截失败的响应
 responseError: function(rejection) {
  // 对失败的响应进行处理
  // ...
  if (canRecover(rejection)) {
  return responseOrNewPromise
  }
  return $q.reject(rejection);
 }
 };
});

随后,我们需要将实现的拦截器加入到$httpProvider.interceptors数组中,此操作一般在config方法中进行:

myApp.config(function($httpProvider) {
 $httpProvider.interceptors.push(MyInterceptor);
});

当然,我们也可以通过匿名factroy的方式实现:

$httpProvider.interceptors.push(function($q) {
 return {
 request: function(config) {
  // bala
 },

 response: function(response) {
  // bala
 },

 // bala
 };
});

可以看到,每个拦截器都可以实现4个可选的处理函数,分别对应请求(成功/失败)和响应(成功/失败)的拦截:

1、request:此函数在$http向Server发送请求之前被调用,在此函数中可以对成功的http请求进行处理,其包含一个http config对象作为参数,这里对config对象具有完全的处理权限,甚至可以重新构造,然后直接返回此对象或返回包含此对象的promise即可。如果返回有误,会造成$http请求失败。如开发中经常需要在请求头中加入token以便验证身份,我们可以作如下处理:

request: function(config) {
 config.headers = config.headers || {};
 if ($window.sessionStorage.token) {
  config.headers['X-Access-Token'] = $window.sessionStorage.token;
 }
 return config || $q.when(config);
}

2、requestError:此方法会在前一个拦截器抛出异常或进行了reject操作时被调用,在这里可以进行恢复请求的操作,或者进行一些对于请求时发起动作的处理(如取消loading等);

3、response:此函数在$http从Server接收到响应时被调用,在此函数中可以对成功的http响应进行处理,这里具有对响应的完全处理权限,甚至可以重新构造,然后直接返回响应或返回包含响应的promise即可。如果返回有误,会造成$http接收响应失败;

4、responseError:此方法会在前一个拦截器抛出异常或进行了reject操作时被调用,在这里可以进行恢复响应的操作,进行一些针对错误的处理。

使用用例

为演示Angular $http拦截器的使用方法,下面通过几个常用的用例来说明:

利用request拦截器模拟实现Angular的XSRF(即CSRF)防御

CSRF,即“跨站请求伪造”,不过不知道为什么Angular将其称为XSRF。当处理与后台交互时,Angular的$http会尝试从客户端cookie中读取一个token,其默认的key为XSRF-TOKEN,并构造一个名为X-XSRF-TOKEN的http头部,与http请求一起发送到后台。Server端就可以根据此token识别出请求来源于同域,当然跨域的请求$http不会加入X-XSRF-TOKEN头部。那我们可以利用request拦截器通过如下方式在同域请求头部中加入此头部以达到模拟Angular的XSRF(即CSRF)防御机制的实现效果:

/**
* 正式开发中Angular会主动进行XSRF防御(只要cookie中存在key为`XSRF-TOKEN`的token),
* 一般不需要手动进行,除非cookie中不存在key为`XSRF-TOKEN`的token,这里只是模拟实现
*/
request: function(config) {
 if(config.url.indexOf('SAME_DOMAIN_API_URL') > -1) {
 config.headers['X-XSRF-TOKEN'] = $cookies.get('XSRF-TOKEN');
 }
 return config;
}

如果初始http请求头部类似于:

"headers": {
 "Accept": "application/json, text/plain, */*"
}

那么经过上述的拦截器后,其http请求头部就变成了:

"headers": {
 "Accept": "application/json, text/plain, */*",
 "X-XSRF-TOKEN": X-XSRF-TOKEN-VALUE
}

利用response拦截器模拟实现Angular JSON易损性(JSON vulnerability)防御

Angular在$http请求安全性方面不仅为我们设计了XSRF(CSRF)防御,而且针对请求JSON数据的Url可能通过类似于<script>标签加载的方式被恶意网站获取到我们的JSON数据的情况,设计了Angular JSON易损性(JSON vulnerability)防御,即Server端返回的JSON数据头部可以添加")]}',\n"字符串,得到包含此前缀的响应数据后,Angular会将此前缀删去,将响应还原成正式的JSON数据。此时我们就可以通过response拦截器模拟此过程:

response: function(response) {
 var data = examineJSONResponse(response); // 假设存在这样一个方法
 if(!data) {
  response = validateJSONResponse(response); // 假设存在这样一个方法
 }
 return response || $q.when(reponse);
}

利用request拦截器和response拦截器计算http请求耗时

这个需求可能在开发中并不常用,这里只是作为同时使用request拦截器和response拦截器的例子,我们可以在request拦截器和response拦截器中分别计时,然后求得其差值即可:

myApp.factory('timestampMarker', [function() {
 return {
  request: function(config) {
   config.requestTimestamp = new Date().getTime();
   return config;
  },
  response: function(response) {
   response.config.responseTimestamp = new Date().getTime();
   return response;
  }
 };
}]);
myApp.config(['$httpProvider', function($httpProvider) {
 $httpProvider.interceptors.push('timestampMarker');
}]);

这样我们在每次请求后台时,就能够计算出相应请求的耗时了,如:

$http.get('https://api.github.com/users/liuwenzhuang/repos').then(function(response) {
 var time = response.config.responseTimestamp - response.config.requestTimestamp;
 console.log('The request took ' + (time / 1000) + ' seconds.');
});

总结

$http作为Angular中的核心service,其功能非常强大便捷,今天描述了其子功能http拦截器的概念和描述方式,有理解不正确的地方,请大家留言告知。

Javascript 相关文章推荐
Extjs 继承Ext.data.Store不起作用原因分析及解决
Apr 15 Javascript
js中单引号与双引号冲突问题解决方法
Oct 04 Javascript
Jquery getJSON方法详细分析
Dec 26 Javascript
Javascript核心读书有感之表达式和运算符
Feb 11 Javascript
AngularJS $injector 依赖注入详解
Sep 14 Javascript
jQuery中checkbox反复调用attr('checked', true/false)只有第一次生效的解决方法
Nov 16 Javascript
JavaScript输出所选择起始与结束日期的方法
Jul 12 Javascript
ionic3 懒加载
Aug 16 Javascript
jQuery+ajax读取json数据并按照价格排序示例
Mar 28 jQuery
微信小程序实现自定义加载图标功能
Jul 19 Javascript
微信小程序的引导页实现代码
Jun 24 Javascript
VUE递归树形实现多级列表
Jul 15 Vue.js
详解vue-cli 脚手架项目-package.json
Jul 04 #Javascript
Angular 2父子组件数据传递之@ViewChild获取子组件详解
Jul 04 #Javascript
详解node如何让一个端口同时支持https与http
Jul 04 #Javascript
Angular 2父子组件之间共享服务通信的实现
Jul 04 #Javascript
jQuery实现动态给table赋值的方法示例
Jul 04 #jQuery
Angular 2父子组件数据传递之局部变量获取子组件其他成员
Jul 04 #Javascript
Angular 4.X开发实践中的踩坑小结
Jul 04 #Javascript
You might like
桌面中心(一)创建数据库
2006/10/09 PHP
php中通过Ajax如何实现异步文件上传的代码实例
2011/05/07 PHP
php+highchats生成动态统计图
2014/05/21 PHP
php返回json数据函数实例
2014/10/09 PHP
php使用sql server验证连接数据库的方法
2014/12/25 PHP
PHP实现获取客户端IP并获取IP信息
2015/03/17 PHP
PHP ADODB生成HTML表格函数rs2html功能【附错误处理函数用法】
2018/05/29 PHP
Laravel关联模型中过滤结果为空的结果集(has和with区别)
2018/10/18 PHP
浏览器加载、渲染和解析过程黑箱简析
2012/11/29 Javascript
如何实现textarea里的不同文本显示不同颜色
2014/01/20 Javascript
JS小游戏之极速快跑源码详解
2014/09/25 Javascript
深入分析JQuery和JavaScript的异同
2014/10/23 Javascript
javascript字符串与数组转换汇总
2015/05/26 Javascript
JavaScript简单遍历DOM对象所有属性的实现方法
2015/10/21 Javascript
javascript实现随机生成DIV背景色
2016/06/20 Javascript
js编写的treeview使用方法
2016/11/11 Javascript
JS出现失效的情况总结
2017/01/20 Javascript
JavaScript数据结构之优先队列与循环队列实例详解
2017/10/27 Javascript
常用的 JS 排序算法 整理版
2018/04/05 Javascript
JS实现前端页面的搜索功能
2018/06/12 Javascript
jQuery的Ajax接收java返回数据方法
2018/08/11 jQuery
vue interceptor 使用教程实例详解
2018/09/13 Javascript
[41:05]Serenity vs Pain 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
Python爬虫常用小技巧之设置代理IP
2018/09/13 Python
PyCharm 设置SciView工具窗口的方法
2019/01/15 Python
python实现K近邻回归,采用等权重和不等权重的方法
2019/01/23 Python
解决python打不开文件(文件不存在)的问题
2019/02/18 Python
pytorch制作自己的LMDB数据操作示例
2019/12/18 Python
Python urlopen()和urlretrieve()用法解析
2020/01/07 Python
python range实例用法分享
2020/02/06 Python
护理专业本科生自荐信
2013/10/01 职场文书
校运会入场式解说词
2014/02/10 职场文书
群众路线教育实践活动学习笔记内容
2014/11/06 职场文书
2016幼儿园教师年度考核评语
2015/12/01 职场文书
详解如何使用Node.js实现热重载页面
2021/05/06 Javascript
浅谈 JavaScript 沙箱Sandbox
2021/11/02 Javascript