【问题标题】:Angularjs $http interceptors - Cannot generate call to requestErrorAngularjs $http拦截器 - 无法生成对requestError的调用
【发布时间】:2017-01-15 07:25:37
【问题描述】:

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

来自 angularjs 文档:

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?

关键段落是:

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

但我认为我正在做它规定的事情,即服务器随机sleep,但没有运气。我从请求中得到了reponseErrors,即服务器响应时出现故障。

2) 大约 1 年前有人问过类似的问题:Angular and Jasmine: How to test requestError / rejection in HTTP interceptor?

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

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

【问题讨论】:

  • 您的所有示例都涉及来自服务器的响应 - 或缺少它,因此它是 responseError。顾名思义,requestError 应该处理 client 端的错误,即当 config 对象不正确时。
  • @estus 感谢指针。在请求中抛出错误并返回 $q.reject() 不起作用。我会尝试下面 rubie_newbie 建议的其他方法。

标签: javascript angularjs angular-http-interceptors


【解决方案1】:

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

TL;DR

拦截器不直观,存在很多“陷阱”。线程作者和我陷入了其中的一些。通过更好地了解幕后发生的执行流程,可以解决此类问题。此线程最具体的问题是本文末尾附近的 Gotchas #3 和 #6。

背景

如您所知,$httpProvider 有一个名为“interceptors”的属性,它以一个空数组开始,可以存储一个或多个 interceptorsinterceptor 是一个具有四种可选方法的对象:requestrequestErrorresponseresponseError 。该文档对这些方法几乎没有提及,而且它所说的内容具有误导性和不完整。目前尚不清楚这些何时被调用以及以什么顺序调用。

举例说明

正如在其他 cmets/answers 中提到的,拦截器方法最终都链接在一个大的承诺链中。如果你不熟悉 Promise,拦截器就没有任何意义($http 服务也没有)。即使你理解了 Promise,拦截器还是有点奇怪。

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

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

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

引起错误的显着怪异(“陷阱”)

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

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

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

  4. 如果最后一个拦截器的 requestrequestError 方法拒绝,则不会发送请求。只有当他们解决时,Angular才会真正尝试发送请求。

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

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

结论

我假设这个帖子的作者很久以前就解决了(不是双关语)他们的问题,但我希望这可以帮助其他人。

【讨论】:

  • 是的,我很久以前就“解决”了,但希望有些人会发现您的回答很有用。如果我再次遇到拦截器问题,我一定会检查它作为参考。我还在使用 AngularJS!还没迈出这一步!
【解决方案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');
}]);

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

【讨论】:

  • 我认为你关于分离拦截器的观点是最重要的。我设法让requestError 被调用。如果我在requestError$q.reject(config),则随后调用responseError - 后跟任何then 错误处理程序。这总是意料之中,还是有办法在requestError 完成交易?
  • 以拒绝结束request*拦截器链,然后它不会发出请求。 $httpforms a promise chain from request interceptors and ends it with a server request。它无法在同一个拦截器中捕获它,因为它从请求拦截器而不是.then(...).catch(...) 生成了.then(..., ...) 链。您不能做出“最终”拒绝,因为如果这是您的问题,每个后续拦截器都应该有机会捕获此拒绝。
  • “以拒绝的方式结束请求拦截器链,然后它不会执行请求” 我确实在 requestError 处理程序中以 $q.reject(config) 结束了请求。 responseError 处理程序随后仍被调用。抱歉,但我不明白你的其余答案。
  • 为了不执行请求,来自最后一个拦截器的 responseError 应该返回一个拒绝。如果有多个带有 responseError 的拦截器,则无法从一个拦截器执行 responseError 钩子并跳过其余拦截器的 responseError 钩子。
  • 是的,这就是 Promise 的工作方式。如上所述,来自所有拦截器的请求钩子都被转换为单个 Promise 链,您不能在链的中间退出。
【解决方案3】:

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

【讨论】:

  • 感谢 @ruby_newbie 指针。我确实尝试在请求处理程序中抛出错误,但仍然收到 responseError。我会按照您的建议尝试格式错误的 json 之类的方法,然后将结果回复给您(希望在接下来的 24 小时内)。
  • 仅供参考,我必须分离拦截器。正如 estus 的回答如下所示。无论如何感谢您的意见。
猜你喜欢
  • 1970-01-01
  • 2019-02-11
  • 1970-01-01
  • 2020-11-08
  • 1970-01-01
  • 2015-03-04
  • 2014-05-26
  • 2018-07-08
  • 1970-01-01
相关资源
最近更新 更多