我正在为基于令牌的restful API编写angularjs客户端。 API中的令牌每小时到期,因此每次令牌在我的客户端过期时,都应该有刷新令牌操作。
处理API调用结果的控制器如下所示:
angular.module('apitestApp')
.controller('MainCtrl', ['$rootScope', '$scope', 'httpService', function ($rootScope, $scope, httpService) {
$scope.messages = [];
var url = $rootScope.domainPath + $rootScope.apiPath + 'messages.json';
httpService.getRequest(url, {}).then(
function (data){
$scope.messages = data;
}
);
}]);
我有一个使用angularjs $ resource
进行API调用的服务angular.module('apitestApp')
.service('httpService', ['$rootScope', '$resource', '$localStorage', function ($rootScope, $resource, $localStorage) {
this.getRequest = function (url, params){
var res = $resource(url, params, {
query: {
method: 'GET',
isArray: true,
headers: { 'Authorization': 'Bearer ' + $localStorage.token.access_token }
}
});
return res.query().$promise;
};
this.refreshToken = function (){
var url = $rootScope.domainPath + this.authPath;
var request = $resource(url);
return request.get({
client_id: this.clientId,
client_secret: this.secret,
grant_type: 'refresh_token',
refresh_token: $localStorage.token.refresh_token
},
function (data){
$localStorage.token = data;
}
).$promise;
};
}]);
最后是一个处理所有未授权请求的拦截器(401),刷新访问令牌并重试失败的请求。
angular.module('apitestApp')
.factory('apiInterceptor', ['$q', '$injector', function ($q, $injector){
//Handling error codes
return {
response : function (response){
return response || $q.when(response);
},
responseError: function (rejection){
switch(rejection.status){
case 400:
console.log("Bad request");
break;
case 401:
var config = rejection.config;
var deferred = $q.defer();
var httpService = $injector.get('httpService');
httpService.refreshToken().then(deferred.resolve, deferred.reject);
return deferred.promise.then(function (){
return httpService.getRequest(config.url, config.params);
});
//break;
case 500:
console.log("Internal server error");
break;
default:
console.log("Another error");
break;
}
return $q.reject(rejection);
}
};
}]);
当访问令牌有效时,我服务中的 getRequest()方法成功返回一个promise,这与我希望拦截器返回但是不一样。如果访问令牌已过期,拦截器会捕获401错误,然后更新访问令牌并最终发出相同的请求,问题是我的控制器没有得到任何响应。
如何执行刷新令牌操作并代表用户返回预期数据?我在拦截器中做错了什么?
答案 0 :(得分:2)
您想要从控制器中删除$ rootScope提供程序,这不是Angular的最佳做法,因为控制器在$ rootScope中拥有自己的范围。服务和工厂可以放在$ rootScope上,因为它不会创建它自己的范围,而是他们会监听自己的事件。
此外,将任何异步活动/ HTTP调用放入服务/工厂是最佳做法。只记得"瘦小的控制者,胖子服务"。
也许尝试使用一种使用某种发布/订阅设计的异步处理程序。现在,如果失败,一旦getRequest函数完成异步,它将调用更新消息的存储值,触发对订阅该方法的任何控制器的范围摘要的更新:
控制器
- (IBAction)save:(id)sender {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
NSString *fullFileName = [NSString stringWithFormat:@"%@/temporaryArray", docDir];
[NSKeyedArchiver archiveRootObject:names toFile:fullFileName];
}
服务
angular.module('apitestApp')
.controller('MainCtrl', ['$scope', 'httpService', function ($scope, httpService) {
$scope.messages = [];
httpService.setPath();
httpService.onMessageReady($scope, function (messagesData) {
$scope.messages = messagesData;
});
}]);