Javascript 仅捕获“的全局错误处理程序”;“未处理”;承诺

Javascript 仅捕获“的全局错误处理程序”;“未处理”;承诺,javascript,angularjs,angular-promise,Javascript,Angularjs,Angular Promise,我的angular应用程序有一个全局错误处理程序,它是作为$http拦截器编写的,但我想更进一步。我想要的是,对于每个失败的$http调用(被拒绝),承诺的任何“链接”消费者都应该首先尝试解决错误,如果仍然无法解决(未捕获),那么我希望全局错误处理程序接管 用例是,我的全局错误处理程序在屏幕顶部显示一个咆哮“警报框”。但是我有几个弹出的模态,我在那里显式地处理错误,在模态本身中显示错误消息。因此,本质上,该模态控制器应将被拒绝的承诺标记为“已处理”。但是,由于拦截器似乎总是第一个在$http错误

我的angular应用程序有一个全局错误处理程序,它是作为
$http拦截器编写的,但我想更进一步。我想要的是,对于每个失败的
$http
调用(被拒绝),承诺的任何“链接”消费者都应该首先尝试解决错误,如果仍然无法解决(未捕获),那么我希望全局错误处理程序接管

用例是,我的全局错误处理程序在屏幕顶部显示一个咆哮“
警报框
”。但是我有几个弹出的模态,我在那里显式地处理错误,在模态本身中显示错误消息。因此,本质上,该模态控制器应将被拒绝的承诺标记为“已处理”。但是,由于拦截器似乎总是第一个在
$http错误上运行,所以我想不出一种方法来实现它

这是我的拦截器代码:

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');
    })
1.解决方案(黑客方式) 您可以通过创建一个服务来实现这一点。由于承诺是可连锁的,并且您基本上在控制器级别标记了一个属性
handled
,因此您应该将此承诺传递给您的服务,它将处理未处理的错误

myService.check(
    $http.get('url/to/the/endpoint')
             .then( succCallback, errorCallback) 
);
2.解决方案(首选方式) 或者更好的解决方案是为$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服务调用将应用给定的成功和失败回调,然后它可以链接自己的失败回调,并检查处理的属性是否为true或false

myhttp服务实现(更新、添加了
setAsHandled
函数,该函数只是可选的,但它是一个更好的解决方案,因为它将所有内容都保存在一个位置(“处理”属性易于更改且位于一个位置):

3.解决办法 与
#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.
             })
    }
}

你想过在服务器端实现它吗?当你说它应该尝试解决时,你能举一个例子吗。不能在服务器上实现,关键是要与promises客户端一起工作。通过尝试解决,我的意思是全局错误处理程序应该是http promise中错误的最后一个捕获程序。当前只是,这是第一件遇到错误的事情。这可能会起作用…我想在我使用
$http
的任何地方删除对
$q
的依赖,但是…可能很容易在
setAsHandled
服务方法中执行拒绝操作。不,您将需要$q,因为您必须在失败的处理程序中拒绝您的承诺。O在你的
get
服务功能中,它不会捕捉到它的失败案例。对,但我是说我不想在我使用的每个地方都注入
$q
,你没有其他选择。如果处理好了,你不需要拒绝你的承诺,也不会弹出窗口。实际上你可以跳过
myhttp.s因此,基本规则是:如果您拒绝失败的处理程序中的承诺,它将弹出,否则它不会。因此,即使您没有失败的回调,它也会弹出,因为它没有被处理。希望这一切都有意义。
//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(){ ... }
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.
             })
    }
}