Как обрабатывать множественные ответы в перехватчике Angle responseError

В настоящее время я использую следующий код, чтобы отбросить запрос, который возвращает 401 из моего API:

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 отдельно? Не идеально, это вызовет многократные вызовы обновления на одной странице, но это улучшит пропущенные данные из-за того, что вызов не перебрасывается.

Скриншот:

2 ответа

Один из подходов состоит в том, чтобы сохранить обещание токена и объединить в цепочку вторую и последующие повторные попытки до завершения обновления токена:

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 обновления токена.

Довольно похожий ответ 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);
            }

AuthService:

...
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;
}
Другие вопросы по тегам