【问题标题】:Infinite loop in interceptor拦截器中的无限循环
【发布时间】:2015-08-16 22:25:33
【问题描述】:

我创建了一个使用 API 的 AngularJS 网站。此 API 提供了一些功能,例如身份验证 (Oauth)。

当API返回401错误时,说明access_token已经过期,需要用refresh_token刷新。

我在 AngularJS 中创建了一个拦截器。它的目标是检查API返回的结果是否为401错误,如果是,则必须刷新令牌,然后处理之前被拒绝的请求。

问题在于拦截器创建了一个无限循环。在初始请求第二次失败后,它应该停止但它没有。

angular.module('myApp')
.factory('authInterceptor', function ($rootScope, $q, $window, $injector) {

  return {

    // If the API returns an error
    'responseError' : function(rejection) {

      // If it's a 401
      if (rejection.status == 401) {

        var deferred = $q.defer();

        $injector.get('$http').post('http://my-api.local/api/oauth/token', {
          grant_type    : 'refresh_token',
          client_id     : 'id',
          client_secret : 'secret',
          refresh_token : $window.sessionStorage.refresh_token
        }, {
          headers : {
            'Content-Type'  : 'application/x-www-form-urlencoded'
          },
          transformRequest  : function(obj) {
            var str = [];
            for(var p in obj)
            str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
            return str.join("&");
          }
        })
        // New token request successfull
        .success(function(refreshResponse) {

          // Processing the failed request again (should fail again because I didn't saved the new tokens)
          $injector.get('$http')(rejection.config).success(function(data) {

            deferred.resolve(data);

          })
          .error(function(error, status) {

            deferred.reject();

          });

          return deferred.promise();

        })
        // New token request failure
        .error(function(error, status) {

          deferred.reject();
          // $location.path('users/login');

          return;

        });

      }
      // If it's another errorenter code here
      else
        return rejection;

    }

  }

});

所以这段代码:

  • 在第一个请求失败时启动
  • 刷新令牌
  • 重试请求但再次失败(
  • 刷新令牌
  • 重试请求但再次失败
  • 刷新令牌
  • 重试请求但再次失败
  • 等等……

【问题讨论】:

  • 这看起来不对:return deferred.promise();。您应该只是返回承诺对象 return deferred.promise 而不是尝试执行它。

标签: angularjs angular-http-interceptors


【解决方案1】:

我在我的应用程序中处理了这个问题。您的刷新请求需要包含一个配置/标题变量,例如skipIntercept: true。然后,当您将此作为失败响应拦截时,您可以检查rejection.config.skipIntercept 变量。如果是真的,你直接去$q.reject(rejection)

你在哪里:

if (rejection.status == 401) {

改成:

if (rejection.status == 401 && !rejection.config.skipIntercept) {

然后在此之上:

     headers : {
        'Content-Type'  : 'application/x-www-form-urlencoded'
     },

你需要添加:

     skipIntercept: true,

     headers: {
        'Content-Type'  : 'application/x-www-form-urlencoded'
     },

PS。 there's an existing solution你可以使用。

【讨论】:

  • 您的解决方案有效,我不再有无限循环!关于您的“现有解决方案”,它看起来不错,但并不适合所有令人耳目一新的令牌东西,是吗?有没有办法让它适应我的需要?我是 Angular 的新手,有点迷茫……
  • @Flobesst 查看 git repo 上的自述文件,它解释了如何使用拦截器。基本上,拦截器会做所有事情,除了刷新请求本身。您只需为拦截器在 401 上引发的事件设置一个事件侦听器 ($rootScope.$on(...)),然后触发刷新请求,然后从那里继续。
猜你喜欢
  • 2017-10-17
  • 2019-11-28
  • 2019-06-14
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多