本地处理Angular $http错误并回退到全局错误处理

3

我有一个基于组件的Angular应用程序,其中各个组件加载其各自的数据。当出现错误时,通常希望组件显示错误消息。

但是,在某些情况下,我希望组件忽略错误,并将其留给一些全局错误处理机制来捕获。

拦截器:

angular.module("...").factory("httpInterceptor", function($q) {
    return {
        responseError: function(response) {
            // (1)
            return $q.reject("I AM CALLED FIRST") 
        }
})

服务:

angular.module("...").service("myService", function($http){
    return {
        fetchData: function(){
            return $http.get("...")    
        }
    }
})

控制器:

angular.module("...").controller("MyController", function(myService){
    myService.fetchData()
        .then(function(){ ... })
        .catch(function() { 
           // (2) 
           //I AM CALLED LAST
        })
})

在大多数情况下,我希望错误处理在控制器中进行(即(2)点)。如果控制器决定忽略错误(省略catch),则拦截器仍然可以捕获错误。问题在于,拦截器不知道控制器是否打算捕获错误,因为它在控制器之前被调用。因此,拦截器不知道是否应该显示错误消息(我不想同时出现全局和本地错误消息)。
如何捕获控制器忽略的HTTP错误?

换句话问:如果在 promise 链中没有处理(捕获)错误,你怎么知道呢? - user89862
3个回答

7

因为 Promises 不知道关于派生 Promise 的任何内容,所以似乎没有办法通过 $http、拦截器和 Promises 来使它变得更美观。

但如果需要,以下是一种丑陋的方法:

$httpProvider.interceptors.push(['$q', '$timeout',
        function ($q, $timeout) {
            return {
                responseError: function (response) {
                    $timeout(function () {
                        if (response.errorHandled) {
                            return;
                        }
                        // global AJAX error handling
                    }, 0);
                    return $q.reject(response);
                }
            };
        }
    ]);

然后在.catch()的某个地方:

.catch(function(response){response.errorHandled = true;})

我记得之前在SO上看到过类似的答案,但是我找不到了。


谢谢,Dmitry。事实上,在你建议同样的解决方案之前,我就已经用这种方式解决了它。我同意这不是很好看,但它运行得很好。也许我应该把这个作为我的问题的答案发布出来。对此我感到抱歉 :-) - Kristian S
这个解决方案的唯一问题是你必须始终提供catch表达式,否则异常将不会被处理,最终在控制台上出现错误。 - Alena Kastsiukavets
@AlenaKastsiukavets 未捕获的异常(或者在这种情况下更确切地说是Promise拒绝)将最终进入全局异常处理程序,大多数人实现的方式是记录错误并重定向到错误页面。如果您希望继续使用未定义的行为,则可以通过不实现全局错误处理程序来实现。 - Dmitry

0

这个方法有点巧妙,但是可以通过一种方式为 $http 请求添加全局回退错误处理程序,以处理未指定 errorCallback 的请求失败情况。

基本上,您需要装饰 $http 服务,使其在未指定 errorCallback 的 $http 请求失败时触发“unhandledHttpError”事件。


这将触发“unhandledHttpError”事件:

$http.get('/invalid/url').then(function() {
    //success handler
});

这将不会触发 'unhandledHttpError' 事件:

$http.get('/invalid/url').then(function() {
    //success handler
}, function() {
    //error handler
});

要处理 'unhandledHttpError' 事件:

$rootScope.$on('unhandledHttpError', function(event, response) {...});

这是一个可行的示例:https://jsfiddle.net/45w6o79p/27/ 在 fiddle 中查看 'myConfig' 方法,以获取您需要粘贴到应用程序中添加 'unhandledHttpError' 事件的 $http 装饰代码。

0

如果您不想在控制器中处理,可以抛出错误并让$exceptionHandler来处理。 您可以在配置阶段创建一个通用的错误处理程序:

$provide.decorator('$exceptionHandler', extendExceptionHandler);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接