Асинхронное обновление токена в httpinterceptor, если next.handle возвращает 401 (неавторизовано) - PullRequest
0 голосов
/ 12 апреля 2019

Я использую HttpInterceptor для применения токена доступа к исходящим httprequests. Перехватчик вызывает getUser (), который возвращает Observable, добавляет токен доступа к запросам. Это все работает отлично и денди. Но сейчас мне нужно, чтобы, если запросы возвращали 401, я хотел обновить токен, а затем снова обработать запрос. Поэтому я улавливаю любые ошибки и вызываю renewToken, который также возвращает Observable. Но проблема в том, что он не имеет доступа к функции обратного вызова renewToken. Таким образом, обновленный токен никогда не применяется, и вызов API никогда не выполняется повторно, однако, возобновление ToToken отображается на вкладке моей сети, и это успешно.

Я удостоверился, что renewToken () действительно работает, заменив первый вызов getUser () на renewToken (), и это работает. Таким образом, я предполагаю, что моя путаница с rxjs и с тем, как связать длинные трубы и т. Д., В этом и состоит.

intercept(
        request: HttpRequest<any>,
        next: HttpHandler
    ): Observable<HttpEvent<any>> {
        if (request.url.includes(environment.apiBaseUrl)) {
            return this.authService.getUser().pipe(
                mergeMap((user: User) => {
                    console.log('in getUser call ' + user.expires_in);
                    if (user) {
                        request = request.clone({
                            setHeaders: {
                                Authorization: `Bearer ${user.access_token}`
                            }
                        });
                    }

                    return next.handle(request).pipe(
                        tap(
                            () => {},
                            (err: any) => {
                                debugger
                                if (err instanceof HttpErrorResponse) {
                                    if (err.status === 401) {
                                        return this.authService.renewToken().pipe(
                                            mergeMap((renewedUser: User) => {
                                                console.log('in renewToken call');
                                                if (renewedUser) {
                                                    console.log(renewedUser.expires_in);
                                                    request = request.clone({
                                                        setHeaders: {
                                                            Authorization: `Bearer ${
                                                                renewedUser.access_token
                                                            }`
                                                        }
                                                    });
                                                }
                                                return next.handle(request).pipe(
                                                    tap(
                                                        () => {},
                                                        newErr => {
                                                            console.log(newErr);
                                                            this.authService.login();
                                                        }
                                                    )
                                                );
                                            }),
                                            catchError(renewError => {
                                                return Observable.throw(renewError);
                                            })
                                        );
                                    }
                                }
                            }
                        )
                    );
                })
            );
        } else {
            return next.handle(request);
        }
    }

Итак, я хочу обновить токен и повторить запрос, если я не авторизован при первом запросе, но я никогда не вхожу в функцию обратного вызова renewToken (), чтобы добавить новый токен доступа и повторить запрос.

Кроме того, в идеале можно использовать свойство expired для пользователя, а если срок его действия истек, обновите токен, а затем обработайте запрос только один раз, но я не знаю, как этого добиться асинхронно.

РЕДАКТИРОВАТЬ: Я почти уверен, что это связано с тем, что я не могу вернуть что-то так, как я думаю, из функции крана. поэтому при попытке вернуть renewToken или next.handle это просто невозможно. Тем не менее я понятия не имею, как на самом деле обновить токен и повторить запрос с новым токеном, если первый запрос возвращает ошибку

1 Ответ

0 голосов
/ 12 апреля 2019

Мне удалось решить мою проблему, заменив tap на catchError, почему я не уверен. Если кто-то знает, пожалуйста, объясните. Если у кого-то есть идея, как обновить токен перед отправкой первого запроса, проверив свойство expired для пользователя и сделав его асинхронным, сообщите мне.

return next.handle(request).pipe(
                        catchError((err: any) => {
                            if (err instanceof HttpErrorResponse) {
                                if (err.status === 401) {
                                    return this.authService.renewToken().pipe(
                                        mergeMap((renewedUser: User) => {
                                            if (renewedUser) {
                                                request = this.addBearerToken(
                                                    request,
                                                    renewedUser.access_token
                                                );
                                            }
                                            return next.handle(request).pipe(
                                                tap(
                                                    () => {},
                                                    newErr => {
                                                        console.log(newErr);
                                                        this.authService.login();
                                                    }
                                                )
                                            );
                                        }),
                                        catchError(renewError => {
                                            return Observable.throw(renewError);
                                        })
                                    );
                                }
                            }
                        })
                    );
...