La manipulation de l'actualisation des jetons à l'aide de rxjs
Depuis que j'ai commencé avec angular2 j'ai mis mes services pour retourner Observables de T. Dans le service, j'aurais la carte (appeler), et les composants à l'aide de ces services serait tout simplement utiliser subscribe() pour attendre la réponse. Pour ces scénarios simples, je n'ai pas vraiment besoin de creuser pour rxjs si tout était ok.
Je veux maintenant est le suivant: je suis à l'aide de l'authentification Oauth2 avec actualisation des jetons. Je veux construire une api de services que tous les autres services, et qui permettra de gérer de manière transparente l'actualisation jeton lorsqu'une erreur 401 est retourné. Ainsi, dans le cas d'un 401, j'ai d'abord chercher un nouveau jeton de la OAuth2 point de terminaison, puis réessayer ma demande avec un nouveau jeton. Ci-dessous est le code qui fonctionne très bien, avec des promesses:
request(url: string, request: RequestOptionsArgs): Promise<Response> {
var me = this;
request.headers = request.headers || new Headers();
var isSecureCall: boolean = true; //url.toLowerCase().startsWith('https://');
if (isSecureCall === true) {
me.authService.setAuthorizationHeader(request.headers);
}
request.headers.append('Content-Type', 'application/json');
request.headers.append('Accept', 'application/json');
return this.http.request(url, request).toPromise()
.catch(initialError => {
if (initialError && initialError.status === 401 && isSecureCall === true) {
//token might be expired, try to refresh token.
return me.authService.refreshAuthentication().then((authenticationResult:AuthenticationResult) => {
if (authenticationResult.IsAuthenticated == true) {
//retry with new token
me.authService.setAuthorizationHeader(request.headers);
return this.http.request(url, request).toPromise();
}
return <any>Promise.reject(initialError);
});
}
else {
return <any>Promise.reject(initialError);
}
});
}
Dans le code ci-dessus, authService.refreshAuthentication() va chercher le nouveau jeton et de le stocker dans localStorage. authService.setAuthorizationHeader va définir le "Autorisation" de l'en-tête de déjà mis à jour jeton. Si vous regardez le catch méthode, vous allez voir qu'il renvoie une promesse (pour l'actualisation de jeton) que dans ses tours va finalement retourner une autre promesse (pour le 2ème essai de la demande).
J'ai essayé de le faire sans avoir recours à des promesses:
request(url: string, request: RequestOptionsArgs): Observable<Response> {
var me = this;
request.headers = request.headers || new Headers();
var isSecureCall: boolean = true; //url.toLowerCase().startsWith('https://');
if (isSecureCall === true) {
me.authService.setAuthorizationHeader(request.headers);
}
request.headers.append('Content-Type', 'application/json');
request.headers.append('Accept', 'application/json');
return this.http.request(url, request)
.catch(initialError => {
if (initialError && initialError.status === 401 && isSecureCall === true) {
//token might be expired, try to refresh token
return me.authService.refreshAuthenticationObservable().map((authenticationResult:AuthenticationResult) => {
if (authenticationResult.IsAuthenticated == true) {
//retry with new token
me.authService.setAuthorizationHeader(request.headers);
return this.http.request(url, request);
}
return Observable.throw(initialError);
});
}
else {
return Observable.throw(initialError);
}
});
}
Le code ci-dessus ne fait pas ce que j'attends: dans le cas d'une réponse 200, correctement renvoie la réponse. Toutefois, si elle l'attrape, la 401, il va réussir à récupérer le nouveau jeton, mais le abonnez-vous wil finalement récupérer un observables au lieu de la réponse. Im deviner que c'est la non Observables qui devrait faire le réessayer.
Je me rends compte que la traduction de la promesse de la façon de travailler sur le rxjs bibliothèque est probablement pas la meilleure façon d'aller, mais je n'ai pas été capable de saisir le "tout est un cours d'eau" de la chose. J'ai essayé quelques autres solutions impliquant flatmap, retryWhen etc ... mais il n'a pas été bien loin, donc, de l'aide est appréciée.
Vous devez vous connecter pour publier un commentaire.
À partir d'un rapide coup d'oeil à ton code, je dirais que ton problème semble être que vous n'êtes pas l'aplatissement de la
Observable
est retourné à partir de larefresh
service.La
catch
opérateur s'attend à ce que vous retournera uneObservable
qu'il va concaténer à la fin de l'échec de l'Observable, de sorte que le ruisseauObserver
ne sait pas la différence.Dans le non-401 cas que vous faites cela correctement par le renvoi d'une Observable qui renvoie l'erreur initiale. Toutefois, dans les actualiser le cas où vous retournez un
Observable
le produit plusObservables
au lieu de simples valeurs.Je vous suggère de changer l'actualisation de la logique:
flatMap
va convertir l'intermédiaireObservables
en un seul flux.Dans la dernière version de RxJs, le
flatMap
opérateur a été renommémergeMap
.switchMap
devrait être utilisé à la place.J'ai créé ce démo de comprendre comment gérer l'actualisation de jeton à l'aide de rxjs. Il fait ceci:
Cette démo ne fait pas de réelle HTTP appels (il simule l'aide de
Observable.create
).Au lieu de cela, l'utiliser pour apprendre à utiliser
catchError
etretry
opérateurs pour résoudre un problème (jeton d'accès a échoué la première fois), puis recommencez l'opération qui a échoué (l'appel de l'API).