【问题标题】:How to handle multiple responses in Angular responseError interceptor如何在 Angular responseError 拦截器中处理多个响应
【发布时间】:2018-01-05 02:43:17
【问题描述】:

我目前正在使用以下代码重新引发从我的 API 返回 401 的请求:

responseError: function(rejection) {
                var authData = localStorageService.get('authorizationData');
                if (rejection.status === 401 && authData) {
                    var authService = $injector.get('authService');
                    var $http = $injector.get('$http');
                    ̶v̶a̶r̶ ̶d̶e̶f̶e̶r̶r̶e̶d̶ ̶=̶ ̶$̶q̶.̶d̶e̶f̶e̶r̶(̶)̶;̶ 

                    var promise = authService.refreshToken();

                    return  ̶d̶e̶f̶e̶r̶r̶e̶d̶.̶ promise.then(function () {
                        return $http(rejection.config);
                    });
                }
                return $q.reject(rejection);
            }

这适用于 1 个请求,但如果我从单个页面返回两个 401,例如当页面加载两个 api 调用以填充不同部分时,它似乎不起作用。如何让我的拦截器重新抛出多个延迟调用?

另外,拦截器不应该为每个 401 单独触发吗?不理想,它会导致单个页面上的多次刷新调用,但由于调用未被重新抛出而导致数据丢失有所改善。

截图:

【问题讨论】:

  • 拦截器不应该为每个 401 单独触发 - 它应该。如果这没有发生,请提供stackoverflow.com/help/mcve。能够复制问题的 plunk/fiddle 可能会有所帮助。
  • 您收到两个 401,因为您同时触发了两个带有过期令牌的 XHR。这会导致什么问题?它最终会得到两个 XHR 的有效数据吗?
  • @georgeawg 我看到的行为是两个异步请求用于填充页面触发,都是 401,第二个(?)请求被重新抛出并说我每次调用都有一个选择,第一个选择是空白,第二个有数据。

标签: angularjs angular-http-interceptors refresh-token


【解决方案1】:

一种方法是保存令牌承诺并链接第二次和后续重试,直到令牌刷新完成:

responseError: function(rejection) {
    var authService = $injector.get('authService');
    var $http = $injector.get('$http');
    var tokenPromise = null;

    var authData = localStorageService.get('authorizationData');
    if (rejection.status === 401 && authData) {

        if (!tokenPromise) {
            tokenPromise = authService.refreshToken()
              .finally(function() {
                tokenPromise = null;
            });
        };  

        return tokenPromise.then(function () {
            return $http(rejection.config);
        });
    } else {
        throw rejection;
    }
}

在上面的示例中,拒绝处理程序创建了一个令牌刷新承诺,并随后在令牌刷新完成(已完成或被拒绝)时将其置空。如果在令牌刷新过程中发生另一个拒绝,则重试链接(并延迟)直到令牌刷新 XHR 完成。

【讨论】:

  • 这听起来完全符合我的需要,但是我发布了一个更新的屏幕截图,其中包含代码,看起来它像我的旧请求一样重新抛出了一个请求。不知道怎么解决,但是上面的 tokenPromise 是怎么知道多个请求的呢?
  • 太棒了。正是我需要的?
【解决方案2】:

非常相似的 georgeawg 答案...

responseError: function(rejection) {
                var authData = localStorageService.get('authorizationData');
                if (rejection.status === 401 && authData && !isAuthRequest() /* If request for refresh token fails itself do not go into loop, i.e. check by url */) {
                    var authService = $injector.get('authService');
                    var $http = $injector.get('$http');

                    var promise = authService.refreshTokenExt(); // look below

                    return  ̶promise.then(function () {
                        return $http(rejection.config);
                    });
                }
                return $q.reject(rejection);
            }

授权服务:

...
var refreshAuthPromise;

service.refreshTokenExt = function() {
  if (refreshAuthPromise == null) {
    refreshAuthPromise = authService.refreshToken().catch(function() {
      // Cant refresh - redirect to login, show error or whatever
    }).finally(function() {
      refreshAuthPromise = null;
    });
  }
  return refreshAuthPromise;
}

【讨论】:

  • 今天早上我试了一下,不幸的是,网络捕获看起来一样。我打算用 Angular 1.6 中的拦截器处理两个异步请求是不可能的。但是,我可以通过在每页级别上链接他们的承诺来使我的调用不异步,然后它就可以工作,所以我想我会选择 B 计划。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-27
  • 2015-11-13
  • 1970-01-01
相关资源
最近更新 更多