我在控制器中使用 promise 在$http
请求后呈现视图。一切正常,除非在 401 错误期间涉及 http 拦截器。发生这种情况时,这就是我面临的问题:
http 拦截器从 api 获取 401 错误,将被拒绝的查询添加到缓冲区并显示登录模式。
登录成功后,再次尝试之前有401的排队api查询,api成功返回请求的数据。
然而发生的情况是,即使从 api 返回数据,角度视图也不会更新。视图仅在手动刷新该状态后更新。
这些是我的代码:
1)http拦截器:
我http-auth-interceptor
在这个使用
$httpProvider.interceptors.push(['$rootScope', '$q', 'httpBuffer', function($rootScope, $q, httpBuffer) {
return {
responseError: function(rejection) {
if (!rejection.config.ignoreAuthModule) {
var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
angular.forEach(rejectionReasons, function(value, key) {
if(rejection.data.error === value) {
var deferred = $q.defer();
httpBuffer.append(rejection.config, deferred);
$rootScope.$broadcast('event:auth-loginRequired', rejection);
return deferred.promise;
}
})
}
// otherwise, default behaviour
return $q.reject(rejection);
}
};
}]);
2)http拦截器手表:
scope.$on('event:auth-loginRequired', function() {
LoginModalService.openLoginModal();
console.log('login needed');
});
scope.$on('event:auth-loginCancelled', function() {
$state.go('index');
});
3) 控制器:
.controller('FetchData', ['$scope', 'DataService',
function($scope, DataService) {
DataService.fetchNamesList()
.success(function(names) {
$scope.namesList = names;
}).error(function(error) {
// The login modal should show if auth error occurs
});
}])
在这里,DataService.fetchNamesList()
从 api 执行获取请求。
如果针对上述情况触发了身份验证拦截器,我可以看到$http $_GET
成功登录后再次尝试,但$scope.namesList
视图中没有更新。
到目前为止我的想法是:
1)我正在考虑为上述内容添加一个额外$watch
的内容,以便它在 http 拦截器之后工作。我想到了这一点,然后我放弃了该选项,因为如果我在一个页面中有多个获取请求(如仪表板),那么观察每个请求都会过火。
2)登录后手动刷新ui路由器状态,如下所示。这可行,但当视图涉及表单提交时,它没有帮助,其中完成的表单将在状态重新加载后被重置:
$state.go($state.current, {}, {reload: true});
所以我确定如何解决这个问题。有人可以在这里指导我吗......
编辑:
在@ChrisFoster 在评论中提出建议后,我移动了return deferred.promise
外部angular.forEach
并稍微更改了 foreach 检查。这似乎在登录后正确更新了视图。但是,现在模式显示每个错误,而不仅仅是拒绝原因中列出的错误:
$httpProvider.interceptors.push(['$rootScope', '$q', 'httpBuffer', function($rootScope, $q, httpBuffer) {
return {
responseError: function(rejection) {
if (!rejection.config.ignoreAuthModule) {
var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
// Loop through each rejection reason and redirect
angular.forEach(rejectionReasons, function(value, key) {
if(!(rejection.data.error === value)) {
return $q.reject(rejection);
}
});
var deferred = $q.defer();
httpBuffer.append(rejection.config, deferred);
$rootScope.$broadcast('event:auth-loginRequired', rejection);
return deferred.promise;
}
// otherwise, default behaviour
return $q.reject(rejection);
}
};
}]);