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

前言

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

什么是拦截器

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

实现拦截器

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拦截器的概念和描述方式,有理解不正确的地方,请大家留言告知。

(0)

相关推荐

  • 浅析AngularJs HTTP响应拦截器

    为何要用拦截器? 任何时候,如果我们想要为请求添加全局功能,例如身份认证.错误处理等,在请求发送给服务器之前或服务器返回时对其进行拦截,是比较好的实现手段. angularJs通过拦截器提供了一个从全局层面进行处理的途径.  拦截器允许你: 通过实现 request 方法拦截请求: 该方法会在 $http 发送请求道后台之前执行,因此你可以修改配置或做其他的操作.该方法接收请求配置对象(request configuration object)作为参数,然后必须返回配置对象或者 promise

  • 快速学习AngularJs HTTP响应拦截器

    任何时候,如果我们想要为请求添加全局功能,例如身份认证.错误处理等,在请求发送给服务器之前或服务器返回时对其进行拦截,是比较好的实现手段. angularJs通过拦截器提供了一个从全局层面进行处理的途径. 四种拦截器 实现 request 方法拦截请求 request: function(config) { // do something on request success return config || $q.when(config); } 该方法会在 $http 发送请求后台之前执行,因

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

    前言 在Angular框架中,创建团队为使用者进行了Ajax请求的封装,并通过$http服务暴露出相关的接口.Angular在其官方文档中指出, $http服务底层针对Web常见的安全攻击做出了相应的对策,也就是说使用$http服务封装的Ajax为使用者提供了更为安全的保障.作为一个框架,保证框架的可用性,适配性是很有必要的. Angular在设计,实现中也体现出来了这样的良好风格.我们通常在使用Ajax时,有时候希望我们能够在请求发起前或接收到请求后做一些相应的处理工作,比如:在请求发起前,在

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

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

  • 详解Vue中使用Axios拦截器

    需求是拦截前端的网络请求和相应. 废话不多说,直接上干货. 我用的是vue-cli3所以这个config文件是我自己创建的. 先介绍env.js //根据不同的环境更改不同的baseUrl let baseUrl = ''; //开发环境下 if (process.env.NODE_ENV == 'development') { baseUrl = ''; } else if (process.env.NODE_ENV == 'production') { baseUrl = '生产地址'; }

  • 详解SpringMVC中使用Interceptor拦截器

    SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理.比如通过它来进行权限验证,或者是来判断用户是否登陆,或者是像12306 那样子判断当前时间是否是购票时间.  一.定义Interceptor实现类 SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的.在SpringMVC 中定义一个Interceptor 非常简单,主要有两种方式,第一种方式是要定义的Interce

  • 详解spring面向切面aop拦截器

    spring中有很多概念和名词,其中有一些名字不同,但是从功能上来看总感觉是那么的相似,比如过滤器.拦截器.aop等. 过滤器filter.spring mvc拦截器Interceptor .面向切面编程aop,实际上都具有一定的拦截作用,都是拦截住某一个面,然后进行一定的处理. 在这里主要想着手的是aop,至于他们的比较,我想等三个都一一了解完了再说,因此这里便不做过多的比较. 在我目前的项目实践中,只在一个地方手动显示的使用了aop,那便是日志管理中对部分重要操作的记录. 据我目前所知,ao

  • 详解Angular.js的$q.defer()服务异步处理

    首先本文以个人目前项目的部分代码为例说明为什么要用deferred. function getBase64(img){//传入图片路径,返回base64 function getBase64Image(img,width,height) { var canvas = document.createElement("canvas"); canvas.width = width ? width : img.width; canvas.height = height ? height : i

  • 详解Angular.js数据绑定时自动转义html标签及内容

    angularJS在进行数据绑定时默认是以字符串的形式数据,也就是对你数据中的html标签不进行转义照单全收,这样提高了安全性,防止html标签的注入攻击,但有时候需要,特别是从数据库读取带格式的文本时,无法正常的显示在页面中. 而要对html进行转义,则需要在数据绑定的html标签中使用ng-bind-html属性,该属性依赖与$sanitize,也就是需要引入angular-sanitize.js文件,并在module定义时注入该服务ngSanitize.比如: html: <span ng

  • 详解Angular.js指令中scope类型的几种特殊情况

    前言 大家都知道在默认情况下,指令应该访问父作用域.如果我们对指令暴露了父控制器的scope,那么指令就可以自由的修改scope属性.在一些情况下,你的指令可能想要添加一些只有内部可以使用的属性和函数,如果我们都在父作用域中完成,可能会污染了父作用域,因此,我们有以下两种选择: 使用父作用域-如果不需要操作父作用域属性,不需要一个新的作用域,可以直接使用父作用域 scope:false 一个子作用域-这个作用域会原型继承父作用域 scope:true 一个隔离的作用域-一个全新的.不继承.独立存

  • 详解Angular动态组件

    使用场景 我们先明确下动态组件的使用场景,在代码运行时要动态加载组件,换成普通人话,代码需要根据具体情况(比如用户的操作,向后台请求结果)确定在某些地方加载某些组件,这些组件不是静态的(不是固定的). 官网的举例就是,构建动态广告条,广告组件不断会推出新的,再用只支持静态组件结构的模板显然是不现实的. 再举一个常见的例子,动态弹出框,弹出的组件是不确定的.不断更新的,这里那里弹出个购买框,那那那又需要弹出样式选择框,静态组件结构模板是不能满足群众日渐增长的需求. 怎么实现 然后我们来找个把手,看

  • Angular中的interceptors拦截器

    废话不多说了,直接给大家贴代码了,具体代码如下所述: <!DOCTYPE html> <html ng-app="nickApp"> <head> <meta charset="UTF-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-

  • 详解node.js中的npm和webpack配置方法

    概述 Node.js用c++语言编写而成的,是一个基于chrome V8引擎的javascript运行环境,让javaScript的运行脱离浏览器服务端,可以使用javaScript语言书写服务器端代码 1.使用node来实现一个http服务器 下面创建了一个端口为8787的服务器.他与php,java等不同,像php本地还要基于阿帕奇服务器,node.js能用代码快速搭建一个服务器. // 引入http模块 var http = require("http"); // 调用http的

随机推荐