(转)Angular中的拦截器Interceptor
原文:Interceptors in AngularJS and Useful Examples
$httpAngularJS 的 $http
服务允许我们通过发送 HTTP 请求方式与后台进行通信。在某些情况下,我们希望可以俘获所有的请求,并且在将其发送到服务端之前进行操作。还有一些情况是,我们希望俘获响应,并且在完成完成调用之前处理它。一个很好例子就是处理全局 http 异常。拦截器(Interceptors)应运而生。本文将介绍 AngularJS 的拦截器,并且给几个有用的例子。
什么是拦截器?
$httpProvider
中有一个 interceptors
数组,而所谓拦截器只是一个简单的注册到了该数组中的常规服务工厂。下面的例子告诉你怎么创建一个拦截器:
module.factory( 'myInterceptor' , [ '$log' , function ($log) { $log.debug( '$log is here to show you that this is a regular factory with injection' ); var myInterceptor = { .... .... .... }; return myInterceptor; }]); |
然后通过它的名字添加到 $httpProvider.interceptors
数组:
module.config([ '$httpProvider' , function ($httpProvider) { $httpProvider.interceptors.push( 'myInterceptor' ); }]); |
拦截器允许你:
通过实现
request
方法拦截请求: 该方法会在$http
发送请求道后台之前执行,因此你可以修改配置或做其他的操作。该方法接收请求配置对象(request configuration object)作为参数,然后必须返回配置对象或者promise
。如果返回无效的配置对象或者 promise 则会被拒绝,导致$http
调用失败。通过实现
response
方法拦截响应: 该方法会在$http
接收到从后台过来的响应之后执行,因此你可以修改响应或做其他操作。该方法接收响应对象(response object)作为参数,然后必须返回响应对象或者promise
。响应对象包括了请求配置(request configuration),头(headers),状态(status)和从后台过来的数据(data)。如果返回无效的响应对象或者 promise 会被拒绝,导致$http
调用失败。通过实现
requestError
方法拦截请求异常: 有时候一个请求发送失败或者被拦截器拒绝了。请求异常拦截器会俘获那些被上一个请求拦截器中断的请求。它可以用来恢复请求或者有时可以用来撤销请求之前所做的配置,比如说关闭进度条,激活按钮和输入框什么之类的。通过实现
responseError
方法拦截响应异常: 有时候我们后台调用失败了。也有可能它被一个请求拦截器拒绝了,或者被上一个响应拦截器中断了。在这种情况下,响应异常拦截器可以帮助我们恢复后台调用。异步操作
有时候需要在拦截器中做一些异步操作。幸运的是, AngularJS 允许我们返回一个 promise
延后处理。它将会在请求拦截器中延迟发送请求或者在响应拦截器中推迟响应。
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; } }; return requestInterceptor; }]); |
这个例子中,请求拦截器使用了一个异步操作,根据结果来更新配置。然后它用更新后的配置继续执行操作。如果 deferred
被拒绝,http 请求则会失败。
响应拦截器的例子一样:
module.factory( 'myInterceptor' , [ '$q' , 'someAsyncService' , function ($q, someAsyncService) { var responseInterceptor = { 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 responseInterceptor; }]); |
只有当 deferred
被解析,请求才算成功,如果 deferred
被拒绝,请求将会失败。
例子
本节中我将提供一些 AngularJS 拦截器的例子,以便让你更好的理解它们是如何使用的,并且可以展示一下它们能怎样帮助你。不过请记住,我这里提供的解决案不一定是最好或者最准确的解决案。
Session 注入(请求拦截器)
这里有两种方式来实现服务端的认证。第一种是传统的 Cookie-Based
验证。通过服务端的 cookies 来对每个请求的用户进行认证。另一种方式是 Token-Based
验证。当用户登录时,他会从后台拿到一个 sessionToken
。sessionToken
在服务端标识了每个用户,并且会包含在发送到服务端的每个请求中。
下面的 sessionInjector
为每个被俘获的请求添加了 x-session-token
头 (如果当前用户已登录):
module.factory( 'sessionInjector' , [ 'SessionService' , function (SessionService) { var sessionInjector = { request: function (config) { if (!SessionService.isAnonymus) { config.headers[ 'x-session-token' ] = SessionService.token; } return config; } }; return sessionInjector; }]); module.config([ '$httpProvider' , function ($httpProvider) { $httpProvider.interceptors.push( 'sessionInjector' ); }]); |
然后创建一个请求:
|
被 sessionInjector
拦截之前的配置对象是这样的:
{ "transformRequest" : [ null ], "transformResponse" : [ null ], "method" : "GET" , "url" : "https://api.github.com/users/naorye/repos" , "headers" : { "Accept" : "application/json, text/plain, */*" } } |
被 sessionInjector
拦截之后的配置对象是这样的:
{ "transformRequest" : [ null ], "transformResponse" : [ null ], "method" : "GET" , "url" : "https://api.github.com/users/naorye/repos" , "headers" : { "Accept" : "application/json, text/plain, */*" , "x-session-token" : 415954427904 } } |
时间戳(请求和响应拦截器)
让我们用拦截器来测一下从后台返回响应需要多少时间。可以通过给每个请求和响应加上时间戳。
module.factory( 'timestampMarker' , [ function () { var timestampMarker = { request: function (config) { config.requestTimestamp = new Date().getTime(); return config; }, response: function (response) { response.config.responseTimestamp = new Date().getTime(); return response; } }; return timestampMarker; }]); module.config([ '$httpProvider' , function ($httpProvider) { $httpProvider.interceptors.push( 'timestampMarker' ); }]); |
然后我们可以这样:
$http.get( 'https://api.github.com/users/naorye/repos' ).then( function (response) { var time = response.config.responseTimestamp - response.config.requestTimestamp; console.log( 'The request took ' + (time / 1000) + ' seconds.' ); }); |
完整代码: example for the Timestamp Marker
请求恢复 (请求异常拦截)
为了演示请求异常拦截,我们需要模拟前一个拦截器拒绝了请求这种情况。我们的请求异常拦截器会拿到被拒绝的原因以及恢复请求。
让我们来创建两个拦截器: requestRejector
和 requestRecoverer
。
module.factory( 'requestRejector' , [ '$q' , function ($q) { var requestRejector = { request: function (config) { return $q.reject( 'requestRejector' ); } }; return requestRejector; }]); module.factory( 'requestRecoverer' , [ '$q' , function ($q) { var requestRecoverer = { requestError: function (rejectReason) { if (rejectReason === 'requestRejector' ) { // Recover the request return { transformRequest: [], transformResponse: [], method: 'GET' , headers: { Accept: 'application/json, text/plain, */*' } }; } else { return $q.reject(rejectReason); } } }; return requestRecoverer; }]); module.config([ '$httpProvider' , function ($httpProvider) { $httpProvider.interceptors.push( 'requestRejector' ); // Removing 'requestRecoverer' will result to failed request $httpProvider.interceptors.push( 'requestRecoverer' ); }]); |
然后,如果你像下面这样请求,我们会在 log 中看到 success
,虽然 requestRejector
拒绝了请求。
console.log( 'success' ); }, function (rejectReason) { console.log( 'failure' ); }); |
完整代码: example for the Request Recover
Session 恢复 (响应异常拦截器)
有时候,我们的单页面应用中,会发生丢失 session 情况。这种情况可能由于 session 过期了或者服务器异常。我们来创建一个拦截器,用于恢复 session 然后自动重新发送原始请求(假设 session 过期的情况)。
为了演示目的,我们来假设发生了 session 过期返回 http 状态码 419。
module.factory( 'sessionRecoverer' , [ '$q' , '$injector' , function ($q, $injector) { var sessionRecoverer = { responseError: function (response) { // Session has expired if (response.status == 419){ var SessionService = $injector.get( 'SessionService' ); var $http = $injector.get( '$http' ); var deferred = $q.defer(); // Create a new session (recover the session) // We use login method that logs the user in using the current credentials and // returns a promise SessionService.login().then(deferred.resolve, deferred.reject); // When the session recovered, make the same backend call again and chain the request return deferred.promise.then( function () { return $http(response.config); }); } return $q.reject(response); } }; return sessionRecoverer; }]); module.config([ '$httpProvider' , function ($httpProvider) { $httpProvider.interceptors.push( 'sessionRecoverer' ); }]); |
以这种方式,如果后台调用失败引起 session 过期,sessionRecoverer
会创建一个新的 session 然后重新调用后台。
(转)Angular中的拦截器Interceptor的更多相关文章
- Spring MVC中的拦截器Interceptor
谈谈spring中的拦截器 在web开发中,拦截器是经常用到的功能.它可以帮我们验证是否登陆.预先设置数据以及统计方法的执行效率等等.今天就来详细的谈一下spring中的拦截器.spring中拦截器主 ...
- springmvc中的拦截器interceptor用法
1.配置拦截器 在springMVC.xml配置文件增加: 1 <mvc:interceptors> 2 <!-- 日志拦截器 --> 3 <mvc:intercepto ...
- springMvc中实现拦截器Interceptor以及添加静态资源映射
这个代码写了很久了,多久呢?2018年12-20号写的.... 废话不多说,简化一下,作为笔记. 注: public class springmvcConfig extends WebMvcConfi ...
- struts2中方法拦截器(Interceptor)的中的excludeMethods与includeMethods的理解
http://www.cnblogs.com/langtianya/archive/2013/04/10/3012205.html
- 二十五、过滤器Filter,监听器Listener,拦截器Interceptor的区别
1.Servlet:运行在服务器上可以动态生成web页面.servlet的声明周期从被装入到web服务器内存,到服务器关闭结束.一般启动web服务器时会加载servelt的实例进行装入,然后初始化工作 ...
- JavaWeb—拦截器Interceptor
1.概念 java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取A ...
- SSM-SpringMVC-33:SpringMVC中拦截器Interceptor讲解
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 拦截器Interceptor: 对处理方法进行双向的拦截,可以对其做日志记录等 我选择的是实现Handler ...
- Java 中的过滤器Filter 和拦截器 Interceptor
1.先说拦截器 Interceptor 本项目以springboot为例: 新建 InterceptorConfig package com.opendev.mystudy.MyInterceptor ...
- Spring中过滤器(Filter)和拦截器(Interceptor)的区别和联系
在我们日常的开发中,我们经常会用到Filter和Interceptor.有时同一个功能.Filter可以做,Interceptor也可以做.有时就需要考虑使用哪一个比较好.这篇文章主要介绍一下,二者的 ...
随机推荐
- Django基础必会
Django基础必会 Django项目目录 mysite -mysite -__init__.py -urls.py(函数和函数的对应关系) -settings.py(Django项目的配置信息) - ...
- RDMA——libibverbs 代码分析(1)
下载libibverbs最新代码,https://downloads.openfabrics.org/verbs/README.html 为1.2.0版本.后面开始逐步分析libibverbs源码. ...
- Ubuntu16.04安装、卸载宝塔软件
宝塔是一款Linux可视化软件 1.一键安装 apt-get install wget && wget -O install.sh http://download.bt.cn/inst ...
- loj6271 「长乐集训 2017 Day10」生成树求和 加强版(矩阵树定理,循环卷积)
loj6271 「长乐集训 2017 Day10」生成树求和 加强版(矩阵树定理,循环卷积) loj 题解时间 首先想到先分开三进制下每一位,然后每一位分别求结果为0,1,2的树的个数. 然后考虑矩阵 ...
- 详细描述一下 Elasticsearch 索引文档的过程 ?
面试官:想了解 ES 的底层原理,不再只关注业务层面了. 解答: 这里的索引文档应该理解为文档写入 ES,创建索引的过程. 文档写入包含:单文档写入和批量 bulk 写入,这里只解释一下:单文档写入流 ...
- spring 支持哪些 ORM 框架?
Hibernate iBatis JPA JDO· OJB
- 智能指针中C++重载'->'符号是怎么实现的
例如下面的代码: class StrPtr{ public: StrPtr() : _ptr(nullptr){} //拷贝构造函数等省略... std::string* operator->( ...
- Tensorflow安装教程(Anaconda)
写在最前: 在安装过程中遇到很多坑,一开始自己从官网下载了Python3.6.3或者Python3.6.5或者Python3.7.1等多个版本,然后直接pip install tensorflow或者 ...
- Altium design使用日常故障总结
1.altiumdesigner09如何将不同的板子拼在一起发给工厂?打开这两个图,其中一个图ctrl+a,ctrl+c,打开另一个图pastespecial.放置时选取一边对齐.制版时告诉厂家做个V ...
- 浅谈JavaScript原型与原型链
对于很多前端开发者而言,JavaScript的原型实在是很让人头疼,所以我这边就整理了一下自己对应原型的一点理解,分享给大家,供交流使用 原型 说起原型,那就不得不说prototype.__proto ...