angular 攔截器

介紹:$http service在Angular中用於簡化與後臺的交互過程,其本質上使用XMLHttpRequestJSONP進行與後臺的數據交互。在與後臺的交互過程當中,可能會對每條請求發送到Server以前進行預處理(如加入token),或者是在Server返回數據到達客戶端還未被處理以前進行預處理(如將非JSON格式數據進行轉換);固然還有可能對在請求和響應過程過發生的問題進行捕獲處理。全部這些需求在開發中都很是常見,因此Angular爲咱們提供了$http攔截器,用來實現上述需求。javascript

Angular的$http攔截器是經過$httpProvider.interceptors數組定義的一組攔截器,每一個攔截器都是實現了某些特定方法的Factory: 
http攔截器html

實現:java

http攔截器通常經過定義factory的方式實現:git

myApp.factory('MyInterceptor', function($q) {return { // 可選,攔截成功的請求 request: function(config) {// 進行預處理// ...return config || $q.when(config); }, // 可選,攔截失敗的請求 requestError: function(rejection) {// 對失敗的請求進行處理// ...if (canRecover(rejection)) { return responseOrNewPromise } return $q.reject(rejection); }, // 可選,攔截成功的響應 response: function(response) {// 進行預處理// ....return response || $q.when(reponse); }, // 可選,攔截失敗的響應 responseError: function(rejection) {// 對失敗的響應進行處理// ...if (canRecover(rejection)) { return responseOrNewPromise } return $q.reject(rejection); } }; });angularjs

隨後,咱們須要將實現的攔截器加入到$httpProvider.interceptors數組中,此操做通常在config方法中進行:github

myApp.config(function($httpProvider) { $httpProvider.interceptors.push(MyInterceptor); });json

固然,咱們也能夠經過匿名factroy的方式實現:api

$httpProvider.interceptors.push(function($q) {return { request: function(config) {// bala }, response: function(response) {// bala }, // bala }; });跨域

能夠看到,每一個攔截器均可以實現4個可選的處理函數,分別對應請求(成功/失敗)和響應(成功/失敗)的攔截:數組

 

  • request:此函數在$http向Server發送請求以前被調用,在此函數中能夠對成功的http請求進行處理,其包含一個http config對象做爲參數,這裏對config對象具備徹底的處理權限,甚至能夠從新構造,而後直接返回此對象或返回包含此對象的promise便可。若是返回有誤,會形成$http請求失敗。如開發中常常須要在請求頭中加入token以便驗證身份,咱們能夠做以下處理:
request: function(config) {
    config.headers = config.headers || {};
    if ($window.sessionStorage.token) {
        config.headers['X-Access-Token'] = $window.sessionStorage.token;
    }
    return config || $q.when(config);
}
  • requestError:此方法會在前一個攔截器拋出異常或進行了reject操做時被調用,在這裏能夠進行恢復請求的操做,或者進行一些對於請求時發起動做的處理(如取消loading等);
  • response:此函數在$http從Server接收到響應時被調用,在此函數中能夠對成功的http響應進行處理,這裏具備對響應的徹底處理權限,甚至能夠從新構造,而後直接返回響應或返回包含響應的promise便可。若是返回有誤,會形成$http接收響應失敗
  • responseError:此方法會在前一個攔截器拋出異常或進行了reject操做時被調用,在這裏能夠進行恢復響應的操做,進行一些針對錯誤的處理

 

使用用例

利用request攔截器模擬實現Angular的XSRF(即CSRF)防護

CSRF,即「跨站請求僞造」,不過不知道爲何Angular將其稱爲XSRF。當處理與後臺交互時,Angular的$http會嘗試從客戶端cookie中讀取一個token,其默認的key爲XSRF-TOKEN,並構造一個名爲X-XSRF-TOKEN的http頭部,與http請求一塊兒發送到後臺。Server端就能夠根據此token識別出請求來源於同域,固然跨域的請求$http不會加入X-XSRF-TOKEN頭部。那咱們能夠利用request攔截器經過以下方式在同域請求頭部中加入此頭部以達到模擬Angular的XSRF(即CSRF)防護機制的實現效果:

/** * 正式開發中Angular會主動進行XSRF防護(只要cookie中存在key爲`XSRF-TOKEN`的token), * 通常不須要手動進行,除非cookie中不存在key爲`XSRF-TOKEN`的token,這裏只是模擬實現 */
request: function(config) {
  if(config.url.indexOf('SAME_DOMAIN_API_URL') > -1) {
    config.headers['X-XSRF-TOKEN'] = $cookies.get('XSRF-TOKEN');
  }
  return config;
}

若是初始http請求頭部相似於:

"headers": {
    "Accept": "application/json, text/plain, */*"
}

那麼通過上述的攔截器後,其http請求頭部就變成了:

"headers": {
    "Accept": "application/json, text/plain, */*",
    "X-XSRF-TOKEN": X-XSRF-TOKEN-VALUE
}

利用response攔截器模擬實現Angular JSON易損性(JSON vulnerability)防護

Angular在$http請求安全性方面不只爲咱們設計了XSRF(CSRF)防護,並且針對請求JSON數據的Url可能經過相似於<script>標籤加載的方式被惡意網站獲取到咱們的JSON數據的狀況,設計了Angular JSON易損性(JSON vulnerability)防護,即Server端返回的JSON數據頭部能夠添加")]}',\n"字符串,獲得包含此前綴的響應數據後,Angular會將此前綴刪去,將響應還原成正式的JSON數據。此時咱們就能夠經過response攔截器模擬此過程:

response: function(response) {
    var data = examineJSONResponse(response); // 假設存在這樣一個方法
    if(!data) {
        response = validateJSONResponse(response); // 假設存在這樣一個方法
    }
    return response || $q.when(reponse);
}

利用request攔截器response攔截器計算http請求耗時

這個需求可能在開發中並不經常使用,這裏只是做爲同時使用request攔截器response攔截器的例子,咱們能夠在request攔截器response攔截器中分別計時,而後求得其差值便可:

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

這樣咱們在每次請求後臺時,就可以計算出相應請求的耗時了,如:

$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.');
});

http攔截器通常經過定義factory的方式實現:

myApp.factory('MyInterceptor', function($q) {
  return {
    // 可選,攔截成功的請求
    request: function(config) {
      // 進行預處理
      // ...
      return config || $q.when(config);
    },

    // 可選,攔截失敗的請求
   requestError: function(rejection) {
      // 對失敗的請求進行處理
      // ...
      if (canRecover(rejection)) {
        return responseOrNewPromise
      }
      return $q.reject(rejection);
    },



    // 可選,攔截成功的響應
    response: function(response) {
      // 進行預處理
      // ....
      return response || $q.when(reponse);
    },

    // 可選,攔截失敗的響應
   responseError: function(rejection) {
      // 對失敗的響應進行處理
      // ...
      if (canRecover(rejection)) {
        return responseOrNewPromise
      }
      return $q.reject(rejection);
    }
  };
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

隨後,咱們須要將實現的攔截器加入到$httpProvider.interceptors數組中,此操做通常在config方法中進行:

myApp.config(function($httpProvider) {
    $httpProvider.interceptors.push(MyInterceptor);
});
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

固然,咱們也能夠經過匿名factroy的方式實現:

$httpProvider.interceptors.push(function($q) {
  return {
   request: function(config) {
       // bala
    },

    response: function(response) {
       // bala
    },

    // bala
  };
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

能夠看到,每一個攔截器均可以實現4個可選的處理函數,分別對應請求(成功/失敗)和響應(成功/失敗)的攔截:

  • request:此函數在$http向Server發送請求以前被調用,在此函數中能夠對成功的http請求進行處理,其包含一個http config對象做爲參數,這裏對config對象具備徹底的處理權限,甚至能夠從新構造,而後直接返回此對象或返回包含此對象的promise便可。若是返回有誤,會形成$http請求失敗。如開發中常常須要在請求頭中加入token以便驗證身份,咱們能夠做以下處理:
request: function(config) {
    config.headers = config.headers || {};
    if ($window.sessionStorage.token) {
        config.headers['X-Access-Token'] = $window.sessionStorage.token;
    }
    return config || $q.when(config);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • requestError:此方法會在前一個攔截器拋出異常或進行了reject操做時被調用,在這裏能夠進行恢復請求的操做,或者進行一些對於請求時發起動做的處理(如取消loading等);
  • response:此函數在$http從Server接收到響應時被調用,在此函數中能夠對成功的http響應進行處理,這裏具備對響應的徹底處理權限,甚至能夠從新構造,而後直接返回響應或返回包含響應的promise便可。若是返回有誤,會形成$http接收響應失敗
  • responseError:此方法會在前一個攔截器拋出異常或進行了reject操做時被調用,在這裏能夠進行恢復響應的操做,進行一些針對錯誤的處理。

使用用例

爲演示Angular $http攔截器的使用方法,下面經過幾個經常使用的用例來講明:

利用request攔截器模擬實現Angular的XSRF(即CSRF)防護

CSRF,即「跨站請求僞造」,不過不知道爲何Angular將其稱爲XSRF。當處理與後臺交互時,Angular的$http會嘗試從客戶端cookie中讀取一個token,其默認的key爲XSRF-TOKEN,並構造一個名爲X-XSRF-TOKEN的http頭部,與http請求一塊兒發送到後臺。Server端就能夠根據此token識別出請求來源於同域,固然跨域的請求$http不會加入X-XSRF-TOKEN頭部。那咱們能夠利用request攔截器經過以下方式在同域請求頭部中加入此頭部以達到模擬Angular的XSRF(即CSRF)防護機制的實現效果:

/** * 正式開發中Angular會主動進行XSRF防護(只要cookie中存在key爲`XSRF-TOKEN`的token), * 通常不須要手動進行,除非cookie中不存在key爲`XSRF-TOKEN`的token,這裏只是模擬實現 */
request: function(config) {
  if(config.url.indexOf('SAME_DOMAIN_API_URL') > -1) {
    config.headers['X-XSRF-TOKEN'] = $cookies.get('XSRF-TOKEN');
  }
  return config;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

若是初始http請求頭部相似於:

"headers": {
    "Accept": "application/json, text/plain, */*"
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

那麼通過上述的攔截器後,其http請求頭部就變成了:

"headers": {
    "Accept": "application/json, text/plain, */*",
    "X-XSRF-TOKEN": X-XSRF-TOKEN-VALUE
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

利用response攔截器模擬實現Angular JSON易損性(JSON vulnerability)防護

Angular在$http請求安全性方面不只爲咱們設計了XSRF(CSRF)防護,並且針對請求JSON數據的Url可能經過相似於<script>標籤加載的方式被惡意網站獲取到咱們的JSON數據的狀況,設計了Angular JSON易損性(JSON vulnerability)防護,即Server端返回的JSON數據頭部能夠添加")]}',\n"字符串,獲得包含此前綴的響應數據後,Angular會將此前綴刪去,將響應還原成正式的JSON數據。此時咱們就能夠經過response攔截器模擬此過程:

response: function(response) {
    var data = examineJSONResponse(response); // 假設存在這樣一個方法
    if(!data) {
        response = validateJSONResponse(response); // 假設存在這樣一個方法
    }
    return response || $q.when(reponse);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

利用request攔截器response攔截器計算http請求耗時

這個需求可能在開發中並不經常使用,這裏只是做爲同時使用request攔截器response攔截器的例子,咱們能夠在request攔截器response攔截器中分別計時,而後求得其差值便可:

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');
}]);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

這樣咱們在每次請求後臺時,就可以計算出相應請求的耗時了,如:

$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.');
});
相關文章
相關標籤/搜索