Angularjs $ http拦截器 - 无法生成对requestError的调用

时间:2016-09-07 14:30:38

标签: javascript angularjs angular-http-interceptors

我正在使用$http拦截器捕获ajax提交后的所有事件。出于某种原因,我无法抛出requestError。我已经设置了一个测试应用来尝试拨打requestError,但到目前为止,我只能获得多个responseErrors

来自 angularjs docs:

  

requestError :当前一个拦截器抛出错误或通过拒绝解决时,会调用拦截器。

这是我的测试代码。

        .factory('httpInterceptor',['$q',function(q){

            var interceptor = {};

            var uniqueId = function uniqueId() {
                return new Date().getTime().toString(16) + '.' + (Math.round(Math.random() * 100000)).toString(16);
            };

            interceptor.request = function(config){
                config.id = uniqueId();
                console.log('request ',config.id,config);
                return config;
            };

            interceptor.response = function(response){
                console.log('response',response);
                return response;                    
            };

            interceptor.requestError = function(config){
                console.log('requestError ',config.id,config);
                return q.reject(config);
            };

            interceptor.responseError = function(response){
                console.log('responseError ',response.config.id,response);
                return q.reject(response);                    
            };

            return interceptor;

        }])

        .config(['$httpProvider',function($httpProvider) {
            $httpProvider.interceptors.push('httpInterceptor');
        }])

        .controller('MainCtrl',['$http',function($http){

            var mainCtrl = this;

            mainCtrl.method = null;
            mainCtrl.url = null;

            var testHttp = function testHttp() {

                $http({method:mainCtrl.method,url:mainCtrl.url}).then(
                        (response)=>{console.log('ok',response);},
                        (response)=>{console.log('reject',response);}
                );
            };

            //api
            mainCtrl.testHttp = testHttp;

        }])

我尝试了多种创建http错误的方法,每次只调用responseError。我尝试过的事情:

  • 让服务器为每个请求返回不同类型的错误,例如400500
  • 随机获取服务器sleep,以便稍后请求在之前的请求之前响应错误。相同的资源,相同的服务器响应。
  • 通过请求不存在的资源来生成404错误。
  • 断开互联网连接(responseError -1)。

类似问题

1)这个问题似乎有答案: When do functions request, requestError, response, responseError get invoked when intercepting HTTP request and response?

关键的paragrapgh是:

  

关键是上述任何一种方法都可以返回   “普通”对象/原语或将用一个解决的承诺   适当的价值。在后一种情况下,下一个拦截器在   queue将等待,直到返回的promise被解决或拒绝。

但我认为我正在做它所规定的内容,即服务器随机sleep,但没有运气。我从请求中得到reponseErrors故障,即服务器响应后。

2)大约一年前提出了类似的问题:Angular and Jasmine: How to test requestError / rejection in HTTP interceptor?

不幸的是,它只提供interceptors的解释。它没有回答我的问题。

我已在 Chrome Firefox 中进行了测试。我希望你理解,我已经尽力找到解决方案,但我还没有找到解决方案。

3 个答案:

答案 0 :(得分:2)

这是因为请求在任何时候都没有被拒绝。应该使用like that

app.factory('interceptor1', ['$q', function ($q) {
  return {
    request: function (config) {
      console.log('request', config);
      if (config.url === 'restricted')
        return $q.reject({ error: 'restricted', config: config });
    }
  };
}]);

app.factory('interceptor2', ['$q', function ($q) {
  return {
    requestError: function (rejection) {
      console.log('requestError', rejection);      
      if (rejection.error === 'restricted')
        return angular.extend(rejection.config, { url: 'allowed' });

      return $q.reject(rejection);
    }
  };
}]);

app.config(['$httpProvider',function($httpProvider) {
  $httpProvider.interceptors.push('interceptor1');
  $httpProvider.interceptors.push('interceptor2');
}]);

请注意,拦截器应该在堆栈中工作(从transform*请求中的$http挂钩开始),因此请求不能在单个拦截器中被拒绝和恢复。

答案 1 :(得分:2)

我知道我来晚了,但是我遇到了同样的问题,但是我没有发现其他答案特别有用。因此,在花了几个小时研究AngularJS拦截器之后,我想分享我学到的东西。

TL; DR

拦截器不直观,并且有很多“陷阱”。我和线程作者陷入其中。这样的问题可以通过更好地了解幕后执行流程来解决。此帖子最具体的地方是帖子末尾的Gotchas#3和#6。

背景

您知道,$ httpProvider具有一个名为“ interceptors”的属性,该属性以一个空数组开头,可以存储一个或多个 interceptors 拦截器是具有四个可选方法的对象: request requestError response responseError 。该文档对这些方法几乎没有说什么,但确实引起误解和不完整。还不清楚何时调用这些命令以及调用顺序。

示例解释

正如其他评论/答案中所述,拦截器方法最终都链接在一起,形成一个很大的承诺链。如果您不熟悉Promise,拦截器将毫无意义($ http服务也不会)。即使您了解了诺言,拦截器还是有点奇怪。

我将向您展示一个示例,而不是试图解释执行流程。假设我已经在$ httpProvider.interceptors数组中添加了以下三个拦截器。

Diagram of 3 interceptors

当我通过$ http发出请求时,幕后发生的执行流程如下所示。请注意,绿色箭头表示该函数已解决,红色箭头表示该函数已被拒绝(如果抛出错误,它将自动发生)。箭头旁边的标签指示已解决或拒绝的值。

enter image description here

哇,那太复杂了!我不会逐步介绍它,但是我想指出一些可能会使程序员挠头的事情。

引起错误的怪异现象(“陷阱”)

  1. 首先要注意的是,与流行的看法相反,将错误的配置对象传递给$ http()不会触发 requestError 函数-它不会触发任何拦截器方法。它将导致正常的旧错误并停止执行。

  2. 流程中没有横向移动-每个解决或拒绝都会将执行向下移动。如果成功处理程序之一(蓝色)中发生错误,则调用同一拦截器中的错误处理程序(橙色);如果存在的话,则称为下一个下一级。这导致陷阱编号3 ...

  3. 如果您在第一个拦截器中定义了 requestError 方法,则它将永远不会被调用。除非我错误地阅读了angularjs库代码,否则在执行流程中似乎完全无法访问此类函数。这就是让我感到困惑的原因,而且似乎也可能是原始问题中的一部分。

  4. 如果最后一个拦截器的 request requestError 方法拒绝,则不会发送该请求。只有解决了,Angular才会实际尝试发送请求。

  5. 如果请求发送失败或响应状态不是2XX,它将拒绝并触发第一个 responseError 。这意味着您的第一个 responseError 方法必须能够处理两种不同的输入:如果“发送”功能失败,则输入将是错误;但是如果响应为401,则输入将为响应对象。

  6. 一旦开始,就无法打破链条。这似乎也是原始问题中的一部分。当最后一个 requestError 拒绝时,它会跳过发送请求,但是会立即调用第一个 responseError 。直到链接完成,执行才会停止,即使某些操作在早期失败。

结论

我认为此线程的作者很早以前就解决了他们的问题(没有双关语),但是我希望这可以帮助其他人。

答案 2 :(得分:0)

您提出了responseError,因为您的所有示例的响应都有错误。您可以通过尝试在请求中发送无效的json或不正确地格式化请求来获取请求错误。