AngularJs HTTP響應攔截器實現登陸、許可權校驗
$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
$http
呼叫失敗。 - 通過實現
response
方法攔截響應: 該方法會在$http
接收到從後臺過來的響應之後執行,因此你可以修改響應或做其他操作。該方法接收響應物件(response object)作為引數,然後必須返回響應物件或者promise
。響應物件包括了請求配置(request configuration),頭(headers),狀態(status)和從後臺過來的資料(data)。如果返回無效的響應物件或者 promise 會被拒絕,導致$http
呼叫失敗。 - 通過實現
requestError
- 通過實現
responseError
方法攔截響應異常: 有時候我們後臺呼叫失敗了。也有可能它被一個請求攔截器拒絕了,或者被上一個響應攔截器中斷了。在這種情況下,響應異常攔截器可以幫助我們恢復後臺呼叫。
angularjs提供四種攔截器,其中兩種成功攔截器(request、response),兩種失敗攔截器(requestError、responseError)。
angular.module("myApp", [])
.factory('httpInterceptor', [ '$q', '$injector',function($q, $injector) {
var httpInterceptor = {
'responseError' : function(response) {
......
return $q.reject(response);
},
'response' : function(response) {
......
return response;
},
'request' : function(config) {
......
return config;
},
'requestError' : function(config){
......
return $q.reject(config);
}
}
return httpInterceptor;
}
因此,我們可以通過攔截器來判斷用於的登陸與許可權問題。
程式碼中的 $rootScope.user是登入後把使用者資訊放到了全域性rootScope上,方便其他地方使用,$rootScope.defaultPage也是預設主頁面,初始化的時候寫死到rootScope裡的。
$rootScope.$on('$stateChangeStart',function(event, toState, toParams, fromState, fromParams){
if(toState.name=='login')return;// 如果是進入登入介面則允許
// 如果使用者不存在
if(!$rootScope.user || !$rootScope.user.token){
event.preventDefault();// 取消預設跳轉行為
$state.go("login",{from:fromState.name,w:'notLogin'});//跳轉到登入介面
}
});
另外還有使用者已經登入,但是登入超時了,還有就是增加後臺介面的判斷來增強安全性。不能完全依靠本地邏輯
我們在model裡面增加一個使用者攔截器,在rensponseError中判斷錯誤碼,丟擲事件讓Contoller或view來處理
app.factory('UserInterceptor', ["$q","$rootScope",function ($q,$rootScope) {
return {
request:function(config){
config.headers["TOKEN"] = $rootScope.user.token;
return config;
},
responseError: function (response) {
var data = response.data;
// 判斷錯誤碼,如果是未登入
if(data["errorCode"] == "500999"){
// 清空使用者本地token儲存的資訊,如果
$rootScope.user = {token:""};
// 全域性事件,方便其他view獲取該事件,並給以相應的提示或處理
$rootScope.$emit("userIntercepted","notLogin",response);
}
// 如果是登入超時
if(data["errorCode"] == "500998"){
$rootScope.$emit("userIntercepted","sessionOut",response);
}
return $q.reject(response);
}
};
}]);
別忘了要註冊攔截器到angularjs的config中哦
app.config(function ($httpProvider) { $httpProvider.interceptors.push('UserInterceptor'); }); |
---|
最後在controller中處理錯誤事件
$rootScope.$on('userIntercepted',function(errorType){
// 跳轉到登入介面,這裡我記錄了一個from,這樣可以在登入後自動跳轉到未登入之前的那個介面
$state.go("login",{from:$state.current.name,w:errorType});
});
最後還可以在loginController中做更多的細節處理
// 如果使用者已經登入了,則立即跳轉到一個預設主頁上去,無需再登入
if($rootScope.user.token){
$state.go($rootScope.defaultPage);
return;
}
另外在登入成功回撥後還可以跳轉到上一次介面,也就是上面記錄的from
var from = $stateParams["from"];
$state.go(from && from != "login" ? from : $rootScope.defaultPage);