javascript
AngularJS 拦截器和好棒例子
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
Interceptors in AngularJS and Useful Examples
有日期,我喜歡。
$httpAngularJS 的 $http 服務(wù)允許我們通過發(fā)送 HTTP 請(qǐng)求方式與后臺(tái)進(jìn)行通信。在某些情況下,我們希望可以俘獲所有的請(qǐng)求,并且在將其發(fā)送到服務(wù)端之前進(jìn)行操作。還有一些情況是,我們希望俘獲響應(yīng),并且在完成完成調(diào)用之前處理它。一個(gè)很好例子就是處理全局 http 異常。攔截器(Interceptors)應(yīng)運(yùn)而生。本文將介紹 AngularJS 的攔截器,并且給幾個(gè)有用的例子。
#什么是攔截器?
$httpProvider 中有一個(gè) interceptors 數(shù)組,而所謂攔截器只是一個(gè)簡單的注冊(cè)到了該數(shù)組中的常規(guī)服務(wù)工廠。下面的例子告訴你怎么創(chuàng)建一個(gè)攔截器:
<!-- lang: js --> 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 數(shù)組:
<!-- lang: js --> module.config(['$httpProvider', function($httpProvider) {$httpProvider.interceptors.push('myInterceptor'); }]);攔截器允許你:
-
通過實(shí)現(xiàn) request 方法攔截請(qǐng)求: 該方法會(huì)在 $http 發(fā)送請(qǐng)求道后臺(tái)之前執(zhí)行,因此你可以修改配置或做其他的操作。該方法接收請(qǐng)求配置對(duì)象(request configuration object)作為參數(shù),然后必須返回配置對(duì)象或者 promise 。如果返回?zé)o效的配置對(duì)象或者 promise 則會(huì)被拒絕,導(dǎo)致 $http 調(diào)用失敗。
-
通過實(shí)現(xiàn) response 方法攔截響應(yīng): 該方法會(huì)在 $http 接收到從后臺(tái)過來的響應(yīng)之后執(zhí)行,因此你可以修改響應(yīng)或做其他操作。該方法接收響應(yīng)對(duì)象(response object)作為參數(shù),然后必須返回響應(yīng)對(duì)象或者 promise。響應(yīng)對(duì)象包括了請(qǐng)求配置(request configuration),頭(headers),狀態(tài)(status)和從后臺(tái)過來的數(shù)據(jù)(data)。如果返回?zé)o效的響應(yīng)對(duì)象或者 promise 會(huì)被拒絕,導(dǎo)致 $http 調(diào)用失敗。
-
通過實(shí)現(xiàn) requestError 方法攔截請(qǐng)求異常: 有時(shí)候一個(gè)請(qǐng)求發(fā)送失敗或者被攔截器拒絕了。請(qǐng)求異常攔截器會(huì)俘獲那些被上一個(gè)請(qǐng)求攔截器中斷的請(qǐng)求。它可以用來恢復(fù)請(qǐng)求或者有時(shí)可以用來撤銷請(qǐng)求之前所做的配置,比如說關(guān)閉進(jìn)度條,激活按鈕和輸入框什么之類的。
-
通過實(shí)現(xiàn) responseError 方法攔截響應(yīng)異常: 有時(shí)候我們后臺(tái)調(diào)用失敗了。也有可能它被一個(gè)請(qǐng)求攔截器拒絕了,或者被上一個(gè)響應(yīng)攔截器中斷了。在這種情況下,響應(yīng)異常攔截器可以幫助我們恢復(fù)后臺(tái)調(diào)用。
#異步操作
有時(shí)候需要在攔截器中做一些異步操作。幸運(yùn)的是, AngularJS 允許我們返回一個(gè) promise 延后處理。它將會(huì)在請(qǐng)求攔截器中延遲發(fā)送請(qǐng)求或者在響應(yīng)攔截器中推遲響應(yīng)。
<!-- lang: js --> 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; }]);這個(gè)例子中,請(qǐng)求攔截器使用了一個(gè)異步操作,根據(jù)結(jié)果來更新配置。然后它用更新后的配置繼續(xù)執(zhí)行操作。如果 deferred 被拒絕,http 請(qǐng)求則會(huì)失敗。
響應(yīng)攔截器的例子一樣:
<!-- lang: js --> 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; }]);只有當(dāng) deferred 被解析,請(qǐng)求才算成功,如果 deferred 被拒絕,請(qǐng)求將會(huì)失敗。
#例子
本節(jié)中我將提供一些 AngularJS 攔截器的例子,以便讓你更好的理解它們是如何使用的,并且可以展示一下它們能怎樣幫助你。不過請(qǐng)記住,我這里提供的解決案不一定是最好或者最準(zhǔn)確的解決案。
##Session 注入(請(qǐng)求攔截器)
這里有兩種方式來實(shí)現(xiàn)服務(wù)端的認(rèn)證。第一種是傳統(tǒng)的 Cookie-Based 驗(yàn)證。通過服務(wù)端的 cookies 來對(duì)每個(gè)請(qǐng)求的用戶進(jìn)行認(rèn)證。另一種方式是 Token-Based 驗(yàn)證。當(dāng)用戶登錄時(shí),他會(huì)從后臺(tái)拿到一個(gè) sessionToken。sessionToken 在服務(wù)端標(biāo)識(shí)了每個(gè)用戶,并且會(huì)包含在發(fā)送到服務(wù)端的每個(gè)請(qǐng)求中。
下面的 sessionInjector 為每個(gè)被俘獲的請(qǐng)求添加了 x-session-token 頭 (如果當(dāng)前用戶已登錄):
<!-- lang: js --> 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'); }]);然后創(chuàng)建一個(gè)請(qǐng)求:
<!-- lang: js --> $http.get('https://api.github.com/users/naorye/repos');被 sessionInjector 攔截之前的配置對(duì)象是這樣的:
<!-- lang: js --> {"transformRequest": [null],"transformResponse": [null],"method": "GET","url": "https://api.github.com/users/naorye/repos","headers": {"Accept": "application/json, text/plain, */*"} }被 sessionInjector 攔截之后的配置對(duì)象是這樣的:
<!-- lang: js --> {"transformRequest": [null],"transformResponse": [null],"method": "GET","url": "https://api.github.com/users/naorye/repos","headers": {"Accept": "application/json, text/plain, */*","x-session-token": 415954427904} }##時(shí)間戳(請(qǐng)求和響應(yīng)攔截器)
讓我們用攔截器來測(cè)一下從后臺(tái)返回響應(yīng)需要多少時(shí)間。可以通過給每個(gè)請(qǐng)求和響應(yīng)加上時(shí)間戳。
<!-- lang: js --> 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'); }]);然后我們可以這樣:
<!-- lang: js --> $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
##請(qǐng)求恢復(fù) (請(qǐng)求異常攔截)
為了演示請(qǐng)求異常攔截,我們需要模擬前一個(gè)攔截器拒絕了請(qǐng)求這種情況。我們的請(qǐng)求異常攔截器會(huì)拿到被拒絕的原因以及恢復(fù)請(qǐng)求。
讓我們來創(chuàng)建兩個(gè)攔截器: requestRejector 和 requestRecoverer。
<!-- lang: js --> 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 requestreturn {transformRequest: [],transformResponse: [],method: 'GET',url: 'https://api.github.com/users/naorye/repos',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'); }]);然后,如果你像下面這樣請(qǐng)求,我們會(huì)在 log 中看到 success,雖然 requestRejector 拒絕了請(qǐng)求。
<!-- lang: js --> $http.get('https://api.github.com/users/naorye/repos').then(function() {console.log('success'); }, function(rejectReason) {console.log('failure'); });完整代碼: example for the Request Recover
##Session 恢復(fù) (響應(yīng)異常攔截器)
有時(shí)候,我們的單頁面應(yīng)用中,會(huì)發(fā)生丟失 session 情況。這種情況可能由于 session 過期了或者服務(wù)器異常。我們來創(chuàng)建一個(gè)攔截器,用于恢復(fù) session 然后自動(dòng)重新發(fā)送原始請(qǐng)求(假設(shè) session 過期的情況)。
為了演示目的,我們來假設(shè)發(fā)生了 session 過期返回 http 狀態(tài)碼 419。
<!-- lang: js --> module.factory('sessionRecoverer', ['$q', '$injector', function($q, $injector) {var sessionRecoverer = {responseError: function(response) {// Session has expiredif (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 promiseSessionService.login().then(deferred.resolve, deferred.reject);// When the session recovered, make the same backend call again and chain the requestreturn deferred.promise.then(function() {return $http(response.config);});}return $q.reject(response);}};return sessionRecoverer; }]); module.config(['$httpProvider', function($httpProvider) {$httpProvider.interceptors.push('sessionRecoverer'); }]);以這種方式,如果后臺(tái)調(diào)用失敗引起 session 過期,sessionRecoverer 會(huì)創(chuàng)建一個(gè)新的 session 然后重新調(diào)用后臺(tái)。
#總結(jié)
在這篇文章里我解釋了關(guān)于 AngularJS 的攔截器的知識(shí),我介紹了 request, response, requestError 和 responseError攔截器,以及講解了如何/何時(shí)使用它們。我也提供了一些現(xiàn)實(shí)的有用的例子,你可以用在你的開發(fā)中。
我希望這篇文章能讓你看得很爽,就像我寫得爽那樣爽。 好運(yùn)! 撓二爺(NaorYe)
轉(zhuǎn)載于:https://my.oschina.net/ilivebox/blog/290881
總結(jié)
以上是生活随笔為你收集整理的AngularJS 拦截器和好棒例子的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: atitit.ajax bp dwr 3
- 下一篇: git版本号管理工具的上手