angular 拦截器
介绍:$http service在Angular中用于简化与后台的交互过程,其本质上使用XMLHttpRequest或JSONP进行与后台的数据交互。在与后台的交互过程中,可能会对每条请求发送到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个可选的处理函数,分别对应请求(成功/失败)和响应(成功/失败)的拦截:
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);
}
requestError:此方法会在前一个拦截器抛出异常或进行了reject操作时被调用,在这里可以进行恢复请求的操作,或者进行一些对于请求时发起动作的处理(如取消loading等);response:此函数在$http从Server接收到响应时被调用,在此函数中可以对成功的http响应进行处理,这里具有对响应的完全处理权限,甚至可以重新构造,然后直接返回响应或返回包含响应的promise即可。如果返回有误,会造成$http接收响应失败;responseError:此方法会在前一个拦截器抛出异常或进行了reject操作时被调用,在这里可以进行恢复响应的操作,进行一些针对错误的处理
使用用例
利用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拦截器一般通过定义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);
}
};
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
随后,我们需要将实现的拦截器加入到$httpProvider.interceptors数组中,此操作一般在config方法中进行:
myApp.config(function($httpProvider) {
$httpProvider.interceptors.push(MyInterceptor);
});
- 1
- 2
- 3
- 1
- 2
- 3
当然,我们也可以通过匿名factroy的方式实现:
$httpProvider.interceptors.push(function($q) {
return {
request: function(config) {
// bala
},
response: function(response) {
// bala
},
// bala
};
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
可以看到,每个拦截器都可以实现4个可选的处理函数,分别对应请求(成功/失败)和响应(成功/失败)的拦截:
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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
requestError:此方法会在前一个拦截器抛出异常或进行了reject操作时被调用,在这里可以进行恢复请求的操作,或者进行一些对于请求时发起动作的处理(如取消loading等);response:此函数在$http从Server接收到响应时被调用,在此函数中可以对成功的http响应进行处理,这里具有对响应的完全处理权限,甚至可以重新构造,然后直接返回响应或返回包含响应的promise即可。如果返回有误,会造成$http接收响应失败;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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如果初始http请求头部类似于:
"headers": {
"Accept": "application/json, text/plain, */*"
}
- 1
- 2
- 3
- 1
- 2
- 3
那么经过上述的拦截器后,其http请求头部就变成了:
"headers": {
"Accept": "application/json, text/plain, */*",
"X-XSRF-TOKEN": X-XSRF-TOKEN-VALUE
}
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
利用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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
利用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');
}]);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15

- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
这样我们在每次请求后台时,就能够计算出相应请求的耗时了,如:
$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.');
});
angular 拦截器的更多相关文章
- Angular白名单&&Angular拦截器 全局通用
//angular 白名单全局通用 app.config([ '$compileProvider', function ($compileProvider) { $compileProvider.aH ...
- angular 用拦截器统一处理http请求和响应 比如加token
想使用angularjs里的htpp向后台发送请求,现在有个用户唯一识别的token想要放到headers里面去,也就是{headres:{'token':1}} index.html里引入以下js: ...
- angular之interceptors拦截器
<!DOCTYPE html> <html ng-app="nickApp"> <head> <meta charset="UT ...
- angular cli http请求封装+拦截器配置+ 接口配置文件
内容:接口配置文件.http请求封装 .拦截器验证登录 1.接口配置文件 app.api.ts import { Component, OnInit } from '@angular/core'; / ...
- angular中的http拦截器Interceptors
在angularJs中增加了一个对全局的http请求统一做出处理的api--interceptors Interceptors 有两个处理时机,分别是: 其它程序代码执行 HTTP 请求之后,在实际从 ...
- angular http interceptors 拦截器使用分享
拦截器 在开始创建拦截器之前,一定要了解 $q和延期承诺api 出于全局错误处理,身份验证或请求的任何同步或异步预处理或响应的后处理目的,希望能够在将请求移交给服务器之前拦截请求,并在将请求移交给服务 ...
- (转)Angular中的拦截器Interceptor
什么是拦截器? 异步操作 例子 Session 注入(请求拦截器) 时间戳(请求和响应拦截器) 请求恢复 (请求异常拦截) Session 恢复 (响应异常拦截器) 转之:http://my.osch ...
- 通过配置http拦截器,来进行ajax请求验证用户登录的页面跳转
在.NET中验证用户是否登录或者是否过期,若需要登录时则将请求转向至登录页面. 这个流程在进行页面请求时是没问题的,能正确进行页面跳转. 然而在使用xmlhttprequest时,或者jq的getJs ...
- AngularJS 拦截器
在需要进行身份验证时,在请求发送给服务器之前或者从服务器返回时对其进行拦截,是比较好的实现手段. 例如,对于身份验证,如果服务器返回401状态码,将用户重定向到登录页面. AngularJS通过拦截器 ...
随机推荐
- iOS字体大小
1,iOS 字体大小单位是pt——磅. 英文字体的1磅,相当于1/72 英寸,约等于1/2.8mm. px:相对长度单位.像素(Pixel).(PS字体) pt:绝对长度单位.点(Point).(iO ...
- CSS的再深入3(更新中···)
在前面,我们学习了标准文档流,但在实际制作的过程中,用标准文档流书写显然是不现实的,因此,我们来了解几种脱离标准文档流的方法: 1.float 浮动 float:left/right:(左浮/右浮) ...
- 如何评价 React 实现的前端 UI 库 material-ui?
作者:知乎用户链接:https://www.zhihu.com/question/51040975/answer/208582603来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...
- vba编程基础2
安装office2010的时候, 最好是 完全安装/完整安装 , 这样可以查阅 excel的 "帮助文档" 帮助文档中包含了更多的/更详细的 参考信息. 普通模块无事件, 只有 子 ...
- LOJ#2427. 「POI2010」珍珠项链 Beads
题目地址 题目链接 题解 不会算复杂度真是致命,暴力枚举k每次计算是n/2+n/3+n/4+...+1的,用调和级数算是\(O(nlogn)\)的... 如果写哈希表的话能够\(O(nlogn)\), ...
- 深度学习课程笔记(六)Error
深度学习课程笔记(六)Error Variance and Bias: 本文主要是讲解方差和偏差: error 主要来自于这两个方面.有可能是: 高方差,低偏差: 高偏差,低方差: 高方差,高偏差: ...
- 数据集是 seq 文件的处理办法
数据集是 seq 文件的处理办法 2017-03-17 最近下了一个数据集,是 seq 格式的,第一次处理这种数据.使用了官方提供的 matlab 工具包:https://pdollar.github ...
- HDU 6155 Subsequence Count(矩阵乘法+线段树+基础DP)
题意 给定一个长度为 \(n\) 的 \(01\) 串,完成 \(m\) 种操作--操作分两种翻转 \([l,r]\) 区间中的元素.求区间 \([l,r]\) 有多少个不同的子序列. \(1 \le ...
- 配置SSH无密码登录
首先进入目录 : /home/zuoyan/.ssh 在-的 .ssh 下 使用命令生成密钥 ssh-keygen -t rsa 敲4下回车 然后将公钥配置到需要的机器上,复制的目标机器最后是用户名 ...
- Luncene学习二《搜索索引》
搜索索引的流程 第一步:创建一个Directory对象,也就是索引库存放的位置 第二步:创建一个IndexReader对象,需要指定Directory对象 第三步:创建一个indexsearcher对 ...