Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle multiple responses in Angular responseError interceptor

I'm currently using the following code to rethrow a request that returns a 401 from my 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);
            }

This works great for 1 request, but it doesn't seem to work if I get two 401s back from a single page, such as when the page is loading with two api calls to populate different sections. How can I get my interceptor to rethrow multiple deferred calls?

Also, shouldn't the interceptor fire for each 401 individually? Not ideal, it would cause multiple refresh calls on a single page, but an improvement from missing data due to a call not being rethrown.

Screenshot:

enter image description here

like image 667
RandomUs1r Avatar asked Jul 28 '17 22:07

RandomUs1r


1 Answers

One approach is to save the token promise and chain the second and subsequent retries until the token refresh is complete:

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;
    }
}

In the above example the rejection handler create a token refresh promise and subsequently nulls it when the token refresh settles (either fulfilled or rejected). If another rejection occurs while the token refresh is in progress, the retry in chained (and delayed) until the token refresh XHR completes.

like image 134
georgeawg Avatar answered Sep 29 '22 03:09

georgeawg