我的角度应用程序有一个全局错误处理程序,写成$http interceptor
,但我想更进一步。我想要的是每个$http
调用失败(被拒绝),承诺的任何“链式”消费者应首先尝试解决错误,如果它仍然未解决(未被捕获),那么我我希望接管全局错误处理程序。
用例是,我的全局错误处理程序在屏幕顶部显示一个咆哮“alert box
”。但是我弹出了几个模态,我在那里显式处理错误,在模态本身显示错误信息。因此,基本上,这个模态控制器应该将被拒绝的承诺标记为“已处理”。但由于拦截器似乎总是第一个在$http error
上运行,我无法想出办法。
这是我的拦截器代码:
angular.module("globalErrors", ['angular-growl', 'ngAnimate'])
.factory("myHttpInterceptor", ['$q', '$log', '$location', '$rootScope', 'growl', 'growlMessages',
function ($q, $log, $location, $rootScope, growl, growlMessages) {
var numLoading = 0;
return {
request: function (config) {
if (config.showLoader !== false) {
numLoading++;
$rootScope.loading = true;
}
return config || $q.when(config)
},
response: function (response) {
if (response.config.showLoader !== false) {
numLoading--;
$rootScope.loading = numLoading > 0;
}
if(growlMessages.getAllMessages().length) { // clear messages on next success XHR
growlMessages.destroyAllMessages();
}
return response || $q.when(response);
},
responseError: function (rejection) {
//$log.debug("error with status " + rejection.status + " and data: " + rejection.data['message']);
numLoading--;
$rootScope.loading = numLoading > 0;
switch (rejection.status) {
case 401:
document.location = "/auth/login";
growl.error("You are not logged in!");
break;
case 403:
growl.error("You don't have the right to do this: " + rejection.data);
break;
case 0:
growl.error("No connection, internet is down?");
break;
default:
if(!rejection.handled) {
if (rejection.data && rejection.data['message']) {
var mes = rejection.data['message'];
if (rejection.data.errors) {
for (var k in rejection.data.errors) {
mes += "<br/>" + rejection.data.errors[k];
}
}
growl.error("" + mes);
} else {
growl.error("There was an unknown error processing your request");
}
}
break;
}
return $q.reject(rejection);
}
};
}]).config(function ($provide, $httpProvider) {
return $httpProvider.interceptors.push('myHttpInterceptor');
})
这是我希望模态承诺调用的粗略代码:
$http.get('/some/url').then(function(c) {
$uibModalInstance.close(c);
}, function(resp) {
if(resp.data.errors) {
$scope.errors = resp.data.errors;
resp.handled = true;
return resp;
}
});
答案 0 :(得分:2)
您可以通过创建为您执行此操作的服务来实现此目的。由于承诺是可链接的,并且您基本上在控制器级别标记了属性handled
,因此您应该将此承诺传递给您的服务,并且它将处理未处理的错误。
myService.check(
$http.get('url/to/the/endpoint')
.then( succCallback, errorCallback)
);
或者更好的解决方案是为$ http创建一个包装器并执行以下操作:
myhttp.get('url/to/the/endpoint', successCallback, failedCallback);
function successCallback(){ ... }
function failedCallback(resp){
//optional solution, you can even say resp.handled = true
myhttp.setAsHandled(resp);
//do not forget to reject here, otherwise the chained promise will be recognised as a resolved promise.
$q.reject(resp);
}
此处myhttp服务调用将应用给定的成功和失败的回调,然后它可以链接自己的faild回调并检查处理的属性是真还是假。
myhttp服务实现(更新后,添加了setAsHandled
功能,这只是可选功能,但它是一个更好的解决方案,因为它可以将所有内容保存在一个地方(属性&#39;处理&#39;易于更改和在一个地方):
function myhttp($http){
var service = this;
service.setAsHandled = setAsHandled;
service.get = get;
function setAsHandled(resp){
resp.handled = true;
}
function get(url, successHandler, failedHandler){
$http.get(url)
.then(successHandler, failedHandler)
.then(null, function(resp){
if(resp.handled !== true){
//your awesome popup message triggers here.
}
})
}
}
与#2
相同,但实现相同所需的代码更少:
myhttp.get('url/to/the/endpoint', successCallback, failedCallback);
function successCallback(){ ... }
function failedCallback(resp){
//if you provide a failedCallback, and you still want to have your popup, then you need your reject.
$q.reject(resp);
}
其他例子:
//since you didn't provide failed callback, it'll treat as a non-handled promise, and you'll have your popup.
myhttp.get('url/to/the/endpoint', successCallback);
function successCallback(){ ... }
myhttp服务实现:
function myhttp($http){
var service = this;
service.get = get;
function get(url, successHandler, failedHandler){
$http.get(url)
.then(successHandler, failedHandler)
.then(null, function(){
//your awesome popup message triggers here.
})
}
}