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

Angularjs $http interceptors - Cannot generate call to requestError

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

来自 angularjs 文档:

requestError: interceptor gets called when a previous interceptor threw an error or resolved with a rejection.

这是我的测试代码。

        .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。我尝试过的事情:

类似问题

1)这个问题好像有答案:

关键段落是:

A key point is that any of the above methods can return either an "normal" object/primitive or a promise that will resolve with an appropriate value. In the latter case, the next interceptor in the queue will wait until the returned promise is resolved or rejected.

但我 认为 我正在做它规定的事情,即由服务器随机 sleep 但运气不好。我从请求中得到 reponseErrors 乱序,即服务器一响应。

2) 大约 1 年前有人问过类似的问题:

很遗憾,它只提供了对interceptors的解释。它没有回答我的问题。

我已经在 ChromeFirefox 中进行了测试。我希望你能理解,我已经尽力找到解决这个问题的办法,但我还没有找到解决办法。

您引发了 responseError,因为您的所有示例的响应都有错误。尝试在您的请求中发送无效的 json 或不正确地格式化您的请求可能会导致请求错误。

发生这种情况是因为请求在任何时候都没有被拒绝。应该使用 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');
}]);

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

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

TL;DR

拦截器不直观,还有很多"gotchas"。线程作者和我陷入了其中的一些。可以通过更好地了解幕后发生的执行流程来解决此类问题。此线程最具体的是接近此 post.

末尾的 Gotchas #3 和 #6

背景

如您所知,$httpProvider 有一个名为 "interceptors" 的 属性,它以一个空数组开始,是一个或多个 拦截器 可以被存储。 interceptor 是一个有四个可选方法的对象:requestrequestError响应,和responseError。该文档对这些方法只字未提,而且它所说的内容具有误导性和不完整性。目前尚不清楚这些调用的时间和顺序。

举例说明

正如在其他 comments/answers 中提到的,拦截器方法最终都在一个大承诺链中链接在一起。如果您不熟悉 promises,拦截器将没有任何意义($http 服务也不会)。就算懂promises,拦截器还是有点奇怪。

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

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

哇,太复杂了!我不会逐步介绍它,但我想指出一些可能会让程序员摸不着头脑的事情。

值得注意的错误原因("Gotchas")

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

  2. 流程中没有横向移动——每次解决或拒绝都会使执行沿着链条向下移动。如果其中一个成功处理程序(蓝色)发生错误,则 not 调用同一拦截器中的错误处理程序(橙色);如果存在,则调用下一层的那个。这导致问题 3...

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

  4. 如果最后一个拦截器的requestrequestError方法reject,则不会发送请求。只有当他们解决后 angular 才会实际尝试发送请求。

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

  6. 锁链一旦启动就无法跳出。这似乎也是原始问题中问题的一部分。当最后一个 requestError 拒绝时,它会跳过发送请求,但会立即调用第一个 responseError。在链接完成之前,执行不会停止,即使早期出现故障也是如此。

结论

我假设这个话题的作者很久以前就解决了(没有双关语意)他们的问题,但我希望这能帮助其他人。