2017-07-28 1 views
6

ich den folgenden Code zur Zeit bin mit einer Anfrage erneut auslösen, die ein 401 aus meiner API gibt:Wie mehrere Antworten in Angular responseError Abfangjäger zu handhaben

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

Dies funktioniert für 1 Anfrage groß, aber es doesn‘ Es scheint zu funktionieren, wenn ich zwei 401s von einer einzelnen Seite zurückbekomme, zum Beispiel wenn die Seite mit zwei API-Aufrufen geladen wird, um verschiedene Abschnitte zu füllen. Wie kann ich meinen Interceptor dazu bringen, mehrere verzögerte Anrufe erneut auszuführen?

Auch sollte der Abfangjäger nicht für jeden 401 einzeln feuern? Nicht ideal, es würde mehrere Auffrischungsaufrufe auf einer einzelnen Seite verursachen, aber eine Verbesserung von fehlenden Daten aufgrund eines Anrufs, der nicht erneut ausgelöst wird.

Screenshot:

enter image description here

+2

* sollte nicht die Abfangjäger Feuer für jede 401 individuell * - es sollte. Wenn dies nicht geschieht, geben Sie http://stackoverflow.com/help/mcve an. Eine Plunk/Geige, die das Problem reproduzieren kann, kann helfen. – estus

+0

Sie erhalten zwei 401, weil Sie parallel zwei XHRs mit veralteten Token abfeuern. Welches Problem verursacht das? Erhält es schließlich gültige Daten für beide XHRs? – georgeawg

+0

@georgeawg Das Verhalten, das ich sehe, ist zwei Async-Anfragen verwendet, um die Seite Feuer auszufüllen, beide 401, die zweite (?) Anfrage wird rethrown und sagen, ich habe eine Auswahl pro Anruf, die erste Auswahl ist leer, die zweite hat Daten. – RandomUs1r

Antwort

1

Ein Ansatz ist die Token-Versprechen und Kette, die zweiten und die nachfolgenden Wiederholungen zu speichern, bis die Token-Refresh abgeschlossen ist:

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

Im obigen Beispiel der Ablehnung Handler erstellt ein Token-Refresh-Versprechen und beendet es anschließend, wenn die Token-Aktualisierung abgeschlossen ist (entweder erfüllt oder abgelehnt). Wenn während der Token-Aktualisierung eine weitere Zurückweisung erfolgt, wird die Wiederholung in der Kette (und verzögert) fortgesetzt, bis die XHR-Token-Aktualisierung abgeschlossen ist.

+0

Das klingt genau wie das, was ich brauche, aber ich habe einen aktualisierten Screenshot mit dem Code an der richtigen Stelle gepostet, sieht aus, als ob es eine einzelne Anfrage wie meine alte reethrows. Ich bin mir nicht sicher, wie ich es beheben kann, aber wie weiß das obige tokenPromise über mehrere Anfragen? – RandomUs1r

1

ganz ähnlich georgeawg Antwort ...

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

Ich habe heute morgen eine Aufnahme gemacht, die Netzwerkaufnahme sieht leider gleich aus. Ich gehe damit vor, das ist unmöglich mit zwei asynchronen Anfragen mit einem Interceptor in Angular 1.6 zu tun. Jedoch kann ich meine Anrufe nicht asynchron machen, indem ich ihre Versprechen auf einer Seite pro Seite lege und dann funktioniert es, also denke ich, dass ich mit Plan B gehe. – RandomUs1r