angularjs中的interceptor和挺好的例子

原文地址:http://www.webdeveasy.com/interceptors-in-angularjs-and-useful-examples/


AngularJS 的 $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;
    }]);

然後通過攔截器的的名字(即myInterceptor)添加到 $httpProvider.interceptors 數組:

module.config(['$httpProvider', function($httpProvider) {  
    $httpProvider.interceptors.push('myInterceptor');
  }]);

攔截器允許你:

  • 通過實現 request 方法攔截request: 該方法會在$http發送請求到後臺之前執行,因此你可以修改配置或做其他的操作。該方法接收請求配置對象(request configuration object)作爲參數,然後必須返回配置對象或者promise 。如果返回無效的配置對象或者 promise 則會被拒絕,導致$http 調用失敗。

  • 通過實現response方法攔截response: 該方法會在$http接收到從後臺過來的響應之後執行,因此你可以修改響應或做其他操作。該方法接收響應對象(response object)作爲參數,然後必須返回響應對象或者promise。響應對象包括了請求配置(request configuration),頭(headers),狀態(status)和從後臺過來的數據(data)。如果返回無效的響應對象或者 promise 會被拒絕,導致$http調用失敗

  • 通過實現requestError方法攔截請求異常: 有時一個請求發送失敗或者被攔截器拒絕了。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;
 }]);

這個例子中,request攔截器使用了一個異步操作,根據結果來更新配置。然後它用更新後的配置繼續執行操作。如果 deferred

 被拒絕,$http 請求則會失敗。

response攔截器的例子也是一樣的:

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 注入(request攔截器)

這裏有兩種方式來實現服務端的認證。第一種是傳統的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');
 }]);

現在創建一個請求:

$http.get('https://api.github.com/users/naorye/repos');

被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',
                        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,雖然requestInjector 拒絕了請求。

$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。

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 credential
                //s 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攔截器,以及講解了如何並且何時使用它們。我也提供了一些現實的有用的例子,你可以用在你的開發中。

我希望這篇文章能讓你看得很爽,就像我寫得爽那樣爽。 

Good luck!

NaorYe


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章