2017-08-02 1 views
1

Ich verwende Angular 2 und RxJS, um Daten von meiner API-Schicht abzurufen. Ich habe einen Basisdienst, den ich geschrieben habe, um mit HTTP-Anfragen umzugehen. Der folgende Code tut dies in meinem Dienst:Wie wiederhole ich eine beobachtbare Aktion nach dem Ausführen einer Aktion in RxJs?

protected apiGet(uri: string): Observable<HttpMappedResponse<T>> { 
    return this.mapAndHandle<T>(this.http.get(uri)); 
} 

private mapAndHandle<T>(observable: Observable<Response>): Observable<HttpMappedResponse<T>> { 
    const o = observable 
     .map(res => { 
      const data = res.json() || {}; 
      const mappedResponse = new HttpMappedResponse<T>(res, data); 
      // Retrieve page information from HTTP headers 
      mappedResponse.pageInfo = new PageInfo(res.headers); 
      return mappedResponse; 
     }) 
     .share(); 

    o.subscribe(null, e => this.errorService.handleHttpResponse(e)); 
    return o; 
} 

Das funktioniert gut und gibt mir alle Daten, die ich brauche, wenn ich apiGet() nennen. Was ich jetzt zu tun versuchen, ist die folgende:

  • Senden Sie eine HTTP-Anfrage
  • Wenn ein 401-Fehler mit einer bestimmten Zeichenfolge zurückgegeben:
    • eine weitere Anforderung an eine andere URL senden
    • aktualisieren Retry einen anderen Dienst
    • die ursprüngliche Anforderung
    • (dann wohl Logik hinzufügen möglich unendliche Wiederholungen zu handhaben)
  • Else
    • Rethrow der ursprünglichen http Fehler
  • Capture-Fehler und handhaben es

Ich habe versucht, mit .catch(), .retryWhen(), .map() und .flatMapTo() ohne Erfolg - am nächsten ist Folgendes:

Aber das gibt mir nicht die richtigen Ergebnisse.

Gibt es einen Operator, den ich verwenden kann, um dies zu tun? retryWhen() scheint das logischste zu sein, aber ich bringe mich immer wieder in ein Chaos mit RxJs!

+0

Lassen Sie mich wissen, ob meine Antwort Sie in die richtige Richtung führt. Es ist alles Pseudocode, aber es sollte Ihnen eine allgemeine Vorstellung davon geben, was Sie tun können (Sie kennen bereits die Schritte, die Sie unternehmen müssen). Verwenden Sie einfach 'flatMap', wenn Sie Ihre Anfrage wiederholen, und Sie können sie im selben beobachtbaren Stream behalten. – Lansana

Antwort

1

Eines der Probleme, die Sie haben, ist, dass Sie Ihre Anrufe nicht verketten. Ihr Refresh-Aufruf sollte an Ihren Wiederholungsversuch angekettet sein und sie sollten flatMap oder etwas Ähnliches nutzen, um es im selben beobachtbaren Stream zu halten.


Werfen Sie einen Blick auf my answer zu dieser Frage.

Dies ist, wie Sie es erreichen können:

Sie müssen den catch Betreiber von RxJS hinzuzufügen. Dies ist, wo ein Fehler sein wird, und Sie können es entsprechend behandeln.

Damit Ihre Aktualisierungslogik den Interceptor durchlaufen kann, müssen Sie den Aufruf zurückgeben, und die Funktion sollte auch Observable zurückgeben. Zum Beispiel Modifizieren der ursprünglichen Logik oben:

this.http.request(url, options) 
     .map((res: Response) => res.json()) 
     .catch((error: any) => { 
      const err = error.json(); 

      // Refresh JWT 
      if (err.status === 401) { 
       // refreshToken makes another HTTP call and returns an Observable. 
       return this.refreshToken(...); 
      } 

      return Observable.throw(err); 
     }); 

Wenn Sie die ursprüngliche Anforderung erneut zu versuchen, der Lage sein wollen, was können Sie tun, ist die ursprünglichen Anforderungsdaten, dass passieren so weiter erfolgreich das Token erfrischende Sie den Anruf wieder machen .Zum Beispiel könnte Ihre refreshToken Funktion wie folgt aussehen:

refreshToken(url: string, options: RequestOptionsArgs, body: any, tokenData: any): Observable<any> 
    return this.post(`${this.url}/token/refresh`, tokenData) 
     .flatMap((res: any) => { 
      // May want to use response data to set new tokens in your local storage or whatever here... 

      // This is where I retry the original request 
      return this.request(url, options, body); 
     }); 
} 
+0

Danke! Ich habe Beispiele von flatMap() gesehen, konnte aber nicht wirklich herausfinden, was es vorher gemacht hat. Ich verbrachte auch ein paar Stunden damit, einen dummen Refactoring-Bug aufzuspüren, den ich in meinen Code einführte, der den Body in meinen POST- und PUT-Befehlen durch die Header ersetzte. Das hat meinem Verständnis hier sicherlich nicht geholfen! – Spikeh

+0

Ich bin froh, dass ich helfen konnte :) Ich steckte auch noch eine Weile fest, aber schließlich fand ich heraus, dass ich 'flatMap' nutzen konnte, um es zu lösen. Sie können das wahrscheinlich viel sauberer machen, aber Sie bekommen jetzt die Idee. – Lansana

+1

Meine vollständige Implementierung ist ziemlich komplex - die Art zu versuchen, Dinge so allgemein wie möglich zu machen :) – Spikeh

Verwandte Themen