8

我目前正在使用以下代码重新抛出从我的 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 单独触发吗?不理想,它会导致单个页面上的多次刷新调用,但由于调用未被重新抛出而导致丢失数据的改进。

截屏:

在此处输入图像描述

4

2 回答 2

3

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

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 完成。

于 2017-07-31T17:38:28.577 回答
1

非常相似的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;
}
于 2017-08-07T17:05:15.130 回答