AngularJS 攔截器和好棒例子


 

目錄[-]

Interceptors in AngularJS and Useful Examples

有日期,我喜歡。


$httpAngularJS 的 $http 服務允許我們通過發送 HTTP 請求方式與后台進行通信。在某些情況下,我們希望可以俘獲所有的請求,並且在將其發送到服務端之前進行操作。還有一些情況是,我們希望俘獲響應,並且在完成完成調用之前處理它。一個很好例子就是處理全局 http 異常。攔截器(Interceptors)應運而生。本文將介紹 AngularJS 的攔截器,並且給幾個有用的例子。

什么是攔截器?

$httpProvider 中有一個 interceptors 數組,而所謂攔截器只是一個簡單的注冊到了該數組中的常規服務工廠。下面的例子告訴你怎么創建一個攔截器:

<!-- 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 數組:

<!-- lang: js --> 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 延后處理。它將會在請求攔截器中延遲發送請求或者在響應攔截器中推遲響應。

<!-- 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; }]); 

這個例子中,請求攔截器使用了一個異步操作,根據結果來更新配置。然后它用更新后的配置繼續執行操作。如果 deferred 被拒絕,http 請求則會失敗。

響應攔截器的例子一樣:

<!-- 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; }]); 

只有當 deferred 被解析,請求才算成功,如果 deferred 被拒絕,請求將會失敗。

例子

本節中我將提供一些 AngularJS 攔截器的例子,以便讓你更好的理解它們是如何使用的,並且可以展示一下它們能怎樣幫助你。不過請記住,我這里提供的解決案不一定是最好或者最准確的解決案。

Session 注入(請求攔截器)

這里有兩種方式來實現服務端的認證。第一種是傳統的 Cookie-Based 驗證。通過服務端的 cookies 來對每個請求的用戶進行認證。另一種方式是 Token-Based 驗證。當用戶登錄時,他會從后台拿到一個 sessionTokensessionToken 在服務端標識了每個用戶,並且會包含在發送到服務端的每個請求中。

下面的 sessionInjector 為每個被俘獲的請求添加了 x-session-token 頭 (如果當前用戶已登錄):

<!-- 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'); }]); 

然后創建一個請求:

<!-- lang: js --> $http.get('https://api.github.com/users/naorye/repos'); 

被 sessionInjector 攔截之前的配置對象是這樣的:

<!-- lang: js --> { "transformRequest": [ null ], "transformResponse": [ null ], "method": "GET", "url": "https://api.github.com/users/naorye/repos", "headers": { "Accept": "application/json, text/plain, */*" } } 

被 sessionInjector 攔截之后的配置對象是這樣的:

<!-- 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 } } 

時間戳(請求和響應攔截器)

讓我們用攔截器來測一下從后台返回響應需要多少時間。可以通過給每個請求和響應加上時間戳。

<!-- 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

請求恢復 (請求異常攔截)

為了演示請求異常攔截,我們需要模擬前一個攔截器拒絕了請求這種情況。我們的請求異常攔截器會拿到被拒絕的原因以及恢復請求。

讓我們來創建兩個攔截器: 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 request return { 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'); }]); 

然后,如果你像下面這樣請求,我們會在 log 中看到 success,雖然 requestRejector 拒絕了請求。

<!-- 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 恢復 (響應異常攔截器)

有時候,我們的單頁面應用中,會發生丟失 session 情況。這種情況可能由於 session 過期了或者服務器異常。我們來創建一個攔截器,用於恢復 session 然后自動重新發送原始請求(假設 session 過期的情況)。

為了演示目的,我們來假設發生了 session 過期返回 http 狀態碼 419。

<!-- lang: js -->
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 然后重新調用后台。

總結

在這篇文章里我解釋了關於 AngularJS 的攔截器的知識,我介紹了 requestresponserequestError 和 responseError攔截器,以及講解了如何/何時使用它們。我也提供了一些現實的有用的例子,你可以用在你的開發中。

我希望這篇文章能讓你看得很爽,就像我寫得爽那樣爽。 
好運! 
撓二爺(NaorYe)

from: http://my.oschina.net/ilivebox/blog/290881


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM