詳解Angular.js中$http攔截器的介紹及使用
前言
$http service在Angular中用于簡(jiǎn)化與后臺(tái)的交互過程,其本質(zhì)上使用XMLHttpRequest或JSONP進(jìn)行與后臺(tái)的數(shù)據(jù)交互。在與后臺(tái)的交互過程中,可能會(huì)對(duì)每條請(qǐng)求發(fā)送到Server之前進(jìn)行預(yù)處理(如加入token),或者是在Server返回?cái)?shù)據(jù)到達(dá)客戶端還未被處理之前進(jìn)行預(yù)處理(如將非JSON格式數(shù)據(jù)進(jìn)行轉(zhuǎn)換);當(dāng)然還有可能對(duì)在請(qǐng)求和響應(yīng)過程過發(fā)生的問題進(jìn)行捕獲處理。所有這些需求在開發(fā)中都非常常見,所以Angular為我們提供了$http攔截器,用來實(shí)現(xiàn)上述需求。
什么是攔截器
顧名思義,攔截器就是在目標(biāo)達(dá)到目的地之前對(duì)其進(jìn)行處理以便處理結(jié)果更加符合我們的預(yù)期。Angular的$http攔截器是通過$httpProvider.interceptors
數(shù)組定義的一組攔截器,每個(gè)攔截器都是實(shí)現(xiàn)了某些特定方法的Factory:
實(shí)現(xiàn)攔截器
http攔截器一般通過定義factory的方式實(shí)現(xiàn):
myApp.factory('MyInterceptor', function($q) { return { // 可選,攔截成功的請(qǐng)求 request: function(config) { // 進(jìn)行預(yù)處理 // ... return config || $q.when(config); }, // 可選,攔截失敗的請(qǐng)求 requestError: function(rejection) { // 對(duì)失敗的請(qǐng)求進(jìn)行處理 // ... if (canRecover(rejection)) { return responseOrNewPromise } return $q.reject(rejection); }, // 可選,攔截成功的響應(yīng) response: function(response) { // 進(jìn)行預(yù)處理 // .... return response || $q.when(reponse); }, // 可選,攔截失敗的響應(yīng) responseError: function(rejection) { // 對(duì)失敗的響應(yīng)進(jìn)行處理 // ... if (canRecover(rejection)) { return responseOrNewPromise } return $q.reject(rejection); } }; });
隨后,我們需要將實(shí)現(xiàn)的攔截器加入到$httpProvider.interceptors
數(shù)組中,此操作一般在config方法中進(jìn)行:
myApp.config(function($httpProvider) { $httpProvider.interceptors.push(MyInterceptor); });
當(dāng)然,我們也可以通過匿名factroy的方式實(shí)現(xiàn):
$httpProvider.interceptors.push(function($q) { return { request: function(config) { // bala }, response: function(response) { // bala }, // bala }; });
可以看到,每個(gè)攔截器都可以實(shí)現(xiàn)4個(gè)可選的處理函數(shù),分別對(duì)應(yīng)請(qǐng)求(成功/失?。┖晚憫?yīng)(成功/失?。┑臄r截:
1、request:此函數(shù)在$http向Server發(fā)送請(qǐng)求之前被調(diào)用,在此函數(shù)中可以對(duì)成功的http請(qǐng)求進(jìn)行處理,其包含一個(gè)http config對(duì)象作為參數(shù),這里對(duì)config對(duì)象具有完全的處理權(quán)限,甚至可以重新構(gòu)造,然后直接返回此對(duì)象或返回包含此對(duì)象的promise即可。如果返回有誤,會(huì)造成$http請(qǐng)求失敗。如開發(fā)中經(jīng)常需要在請(qǐng)求頭中加入token以便驗(yàn)證身份,我們可以作如下處理:
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:此方法會(huì)在前一個(gè)攔截器拋出異?;蜻M(jìn)行了reject操作時(shí)被調(diào)用,在這里可以進(jìn)行恢復(fù)請(qǐng)求的操作,或者進(jìn)行一些對(duì)于請(qǐng)求時(shí)發(fā)起動(dòng)作的處理(如取消loading等);
3、response:此函數(shù)在$http從Server接收到響應(yīng)時(shí)被調(diào)用,在此函數(shù)中可以對(duì)成功的http響應(yīng)進(jìn)行處理,這里具有對(duì)響應(yīng)的完全處理權(quán)限,甚至可以重新構(gòu)造,然后直接返回響應(yīng)或返回包含響應(yīng)的promise即可。如果返回有誤,會(huì)造成$http接收響應(yīng)失??;
4、responseError:此方法會(huì)在前一個(gè)攔截器拋出異?;蜻M(jìn)行了reject操作時(shí)被調(diào)用,在這里可以進(jìn)行恢復(fù)響應(yīng)的操作,進(jìn)行一些針對(duì)錯(cuò)誤的處理。
使用用例
為演示Angular $http攔截器的使用方法,下面通過幾個(gè)常用的用例來說明:
利用request攔截器模擬實(shí)現(xiàn)Angular的XSRF(即CSRF)防御
CSRF,即“跨站請(qǐng)求偽造”,不過不知道為什么Angular將其稱為XSRF。當(dāng)處理與后臺(tái)交互時(shí),Angular的$http會(huì)嘗試從客戶端cookie中讀取一個(gè)token,其默認(rèn)的key為XSRF-TOKEN,并構(gòu)造一個(gè)名為X-XSRF-TOKEN的http頭部,與http請(qǐng)求一起發(fā)送到后臺(tái)。Server端就可以根據(jù)此token識(shí)別出請(qǐng)求來源于同域,當(dāng)然跨域的請(qǐng)求$http不會(huì)加入X-XSRF-TOKEN頭部。那我們可以利用request攔截器通過如下方式在同域請(qǐng)求頭部中加入此頭部以達(dá)到模擬Angular的XSRF(即CSRF)防御機(jī)制的實(shí)現(xiàn)效果:
/** * 正式開發(fā)中Angular會(huì)主動(dòng)進(jìn)行XSRF防御(只要cookie中存在key為`XSRF-TOKEN`的token), * 一般不需要手動(dòng)進(jìn)行,除非cookie中不存在key為`XSRF-TOKEN`的token,這里只是模擬實(shí)現(xiàn) */ request: function(config) { if(config.url.indexOf('SAME_DOMAIN_API_URL') > -1) { config.headers['X-XSRF-TOKEN'] = $cookies.get('XSRF-TOKEN'); } return config; }
如果初始http請(qǐng)求頭部類似于:
"headers": { "Accept": "application/json, text/plain, */*" }
那么經(jīng)過上述的攔截器后,其http請(qǐng)求頭部就變成了:
"headers": { "Accept": "application/json, text/plain, */*", "X-XSRF-TOKEN": X-XSRF-TOKEN-VALUE }
利用response攔截器模擬實(shí)現(xiàn)Angular JSON易損性(JSON vulnerability)防御
Angular在$http請(qǐng)求安全性方面不僅為我們?cè)O(shè)計(jì)了XSRF(CSRF)防御,而且針對(duì)請(qǐng)求JSON數(shù)據(jù)的Url可能通過類似于<script>標(biāo)簽加載的方式被惡意網(wǎng)站獲取到我們的JSON數(shù)據(jù)的情況,設(shè)計(jì)了Angular JSON易損性(JSON vulnerability)防御,即Server端返回的JSON數(shù)據(jù)頭部可以添加")]}',\n"字符串,得到包含此前綴的響應(yīng)數(shù)據(jù)后,Angular會(huì)將此前綴刪去,將響應(yīng)還原成正式的JSON數(shù)據(jù)。此時(shí)我們就可以通過response攔截器模擬此過程:
response: function(response) { var data = examineJSONResponse(response); // 假設(shè)存在這樣一個(gè)方法 if(!data) { response = validateJSONResponse(response); // 假設(shè)存在這樣一個(gè)方法 } return response || $q.when(reponse); }
利用request攔截器和response攔截器計(jì)算http請(qǐng)求耗時(shí)
這個(gè)需求可能在開發(fā)中并不常用,這里只是作為同時(shí)使用request攔截器和response攔截器的例子,我們可以在request攔截器和response攔截器中分別計(jì)時(shí),然后求得其差值即可:
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'); }]);
這樣我們?cè)诿看握?qǐng)求后臺(tái)時(shí),就能夠計(jì)算出相應(yīng)請(qǐng)求的耗時(shí)了,如:
$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.'); });
總結(jié)
$http作為Angular中的核心service,其功能非常強(qiáng)大便捷,今天描述了其子功能http攔截器的概念和描述方式,有理解不正確的地方,請(qǐng)大家留言告知。
相關(guān)文章
基于angular6.0實(shí)現(xiàn)的一個(gè)組件懶加載功能示例
這篇文章主要介紹了基于angular6.0實(shí)現(xiàn)的一個(gè)組件懶加載功能示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-04-04使用Angular.js實(shí)現(xiàn)簡(jiǎn)單的購(gòu)物車功能
在各大購(gòu)物網(wǎng)站大家都可以簡(jiǎn)單購(gòu)物車效果演示,下面通過本文給大家分享一段代碼關(guān)于使用Angular.js實(shí)現(xiàn)簡(jiǎn)單的購(gòu)物車功能,需要的朋友可以參考下2016-11-11AngularJS實(shí)現(xiàn)動(dòng)態(tài)切換樣式的方法分析
這篇文章主要介紹了AngularJS實(shí)現(xiàn)動(dòng)態(tài)切換樣式的方法,結(jié)合實(shí)例形式分析了AngularJS事件響應(yīng)與樣式動(dòng)態(tài)控制相關(guān)操作技巧,需要的朋友可以參考下2018-06-06詳解關(guān)于Angular4 ng-zorro使用過程中遇到的問題
這篇文章主要介紹了詳解關(guān)于Angular4 ng-zorro使用過程中遇到的問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-12-12AngularJs導(dǎo)出數(shù)據(jù)到Excel的示例代碼
本篇文章主要介紹了AngularJs導(dǎo)出Excel的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08