$http服务允许我们使用http请求和后台做通信,但是在每一次放松请求之前我们都希望能够捕捉这个请求并且进行操作,比如之前富瑞中每一个请求中header要放入用户名和密码一样,富瑞的做法是放了一个全局变量,但是这个方法是非常不可取的!全部变量污染的问题,所以在angularjs指令中的拦截器就是个很好的解决方案!然后对于http请求的一些服务也可以有一个很好的统一的处理方法
下面具体说下$httpprovider中的interceptors,下面称之为拦截器
其实也就是$httpprovider服务包含一个拦截器数组,是一个简单的factory注册进来的。
创建拦截器:
写一个factory
angular.module('pldApp.services', []) .factory('authInterceptor',function () { return { request: function (config) { config.headers = config.headers || {}; var token = JSON.parse(window.localStorage.getItem("token")) || ""; config.headers.Authorization = 'Bearer ' + token.access_token; return config; } }; });
config里面配置
$httpProvider.interceptors.push('authInterceptor');
然后在每一次发送请求的时候都调用request方法,这里我打印了config的具体信息,其实这里大家可以看到请求的具体内容,然后我们可以在他发送请求之前大肆的改动请求的内容。
这里我用的是request方法
拦截器允许有一下四个操作:
1、 请求的拦截:request
这个方法的调用在$http请求之前
所以在此之前我们可以修改配置和进行其他操作!
2、 拦截响应:response
当$http服务收到后台给出响应的时候,这个方法被调用。所以我们可以修改请求响应。这个方法接受一个响应对象作为参数。响应对象包含请求配置、标题、状态以及从后台返回的数据。如果返回的是一个无效的对象或者是promise,这个是不会调用的。
3、 拦截请求错误:requestError
4、 拦截响应错误:responseError
这里注意拦截响应错误!!!当你的controller这么写的时候
$scope.getLogin = function(){ $scope.myLoading(); loginService.getLogin($scope.user.name,$scope.user.paw).success(function(data){ window.localStorage.setItem("token",JSON.stringify(data)); window.localStorage.setItem("username",$scope.user.name); window.localStorage.setItem("password",$scope.user.paw); //获取用户信息 loginService.getUserInfo().success(function(data){ mineService.setInifo(data); }).error(function(status,error){ $ionicLoading.show({ template:chargeStatus(status) }); }); $scope.lodingHide(); $scope.skipPage('tab.homePage'); }).error(function(error,status){ $ionicLoading.show({ template:chargeStatus(status) }); $timeout(function () { $ionicLoading.hide(); },2000); }); };
如果登录名和密码错误了,但是你依旧这么封装responseError的话,controller会执行成功毁掉函数的
所以这里我们其实需要自己重新封装个promise的,这样才能够让controller中执行失败的回调函数。
所以上面三个我的写法是这样的
angular.module('pldApp.services', []) .factory('authInterceptor',function ($q) { return { request: function (config) { config.headers = config.headers || {}; var token = JSON.parse(window.localStorage.getItem("token")) || ""; config.headers.Authorization = 'Bearer ' + token.access_token; return config; }, response: function(response) { console.log("response:"); console.log(response); return response; }, responseError:function(errorReason){ console.log(errorReason); return $q.reject(errorReason); }, requestError:function(errorReason){ console.log(2); return $q.reject(errorReason); } }; });
因为这个我也接触的不是特别深入,所以这里给大家只是简单的介绍了下基本用法
下面是从网上找的一些引用:
异步操作:
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; }]);
Session 拦截器
现在创建一个get请求:
$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('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'); }]);
Session recover拦截器的使用
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'); }]);
这里就是说道了,要重新封装promise。
这一块其实我也只是刚刚踏入了解,如果后续大家有研究,可以互相讨论讨论!
说到这,是不是发现$q很有搞头?!有必要研究下?!