navigateByUrl, по-видимому, «не происходит» в Safari, если перехватчик не выполняет предыдущий запрос

#angular #safari #jwt #interceptor

Вопрос:

У меня есть проект, в котором перехватчик настроен для обновления токена JWT, если http-запрос выполняется после истечения срока его действия, и пользователь решил остаться в системе (которая хранится, как и сами токены, в локальном хранилище).

Часть этого процесса обновления включает проверку, которая может изменить состояние входа пользователей (посредством субъекта отслеживания состояния в пользовательской службе), если обновление завершится неудачно или пользователь не решил остаться в системе.

Я подписался на это изменение состояния в главном компоненте приложения, и когда он обнаружит, что пользователь вышел из системы, он перейдет (с помощью router.navigateByUrl) пользователя на страницу входа.

Это правильно работает в любом браузере, кроме safari. И я действительно изо всех сил пытаюсь понять, почему это не удается. Сначала я подумал, что, возможно, это был молчаливый сбой, потому что я неправильно обрабатывал исключение обновления, но после явного обнаружения этой ошибки и выписки из журнала консоли, демонстрирующей вызов «navigateByUrl», фактически выполняется (путем размещения консоли.выписка из журнала в .затем обратный вызов вызова) Я совершенно не понимаю, почему браузер не обновляется.

       // app.component catching the sign out to redirect user, note the 'Nav to the home page worked'
       this.userService.getSignInStateSubject().subscribe(state => {
            // if we were signed in and now we are not, redirect user immediately
            console.log('why has this not changed', state, this.signedInState);
            if (!state amp;amp; this.signedInState) {
                // adding cleanup for log out here, rather than scatter it all over the place
                this.productService.setCurrentSelectedProduct(undefined);
                console.log('this needs to change immediately');
                this.routerService.navigateByUrl('/login').then(success => {
                    console.log('Nav to the home page worked');
                }, error => {
                    console.log(error);
                });
            }
            this.signedInState = state;
        });
 
 // auth interceptor
return next.handle(authReq).pipe(catchError(err => {
            // we need to make sure we dont try to refresh on authentication failure
            if ([400, 401].indexOf(err.status) > -1 amp;amp; req.url !== environment.api_url   '/'   environment.tokens) {
                userService.redirectUrl = routingService.url;
                // convert to an observable and pipe the result
                return from(userService.attemptTokenRefresh()).pipe(
                    catchError(error => {
                        console.log('this caught the error and did nothing with it');
                        return of(error);
                    }),
                    switchMap(result => {
                        console.log('result', result);
                        if (result instanceof String) {
                            console.log('this got a real result');
                            authReq = req.clone({
                                setHeaders: { Authorization: 'Bearer '   result }
                            });
                            return next.handle(authReq);
                        } else {
                            console.log('this has not worked well at all', result);
                            return EMPTY;
                        }
                    }),
                );
            } else {
                return throwError(err);
            }
        }));
 
 \ user service 'refresh' method
public attemptTokenRefresh(): Promise<string> {
        return new Promise((resolve, reject) => {
            // console.log('here we are doing the refresh', localStorage.getItem(this.STAY_SIGNED_IN_KEY), Boolean(Number(localStorage.getItem(this.STAY_SIGNED_IN_KEY))), localStorage.getItem(this.REFRESH_TOKEN_KEY));
            // reject if user chose not to stay signed in
            if (!Boolean(Number(localStorage.getItem(this.STAY_SIGNED_IN_KEY)))) {
                this.clearStoredData();
                this.userSubject.next(undefined);
                reject('Refresh failed as user chose not to stay signed in');
                return;
            }

            const refreshToken = localStorage.getItem(this.REFRESH_TOKEN_KEY);
            // reject if we have a missing or invalid refresh token
            if (!refreshToken) {
                this.clearStoredData();
                this.userSubject.next(undefined);
                reject('Refresh failed because of invalid refresh token');
                return;
            }

            // attempt a refresh
            this.httpClient.post(environment.api_url   '/'   environment.refresh_tokens, JSON.stringify({ refreshToken }), {
                headers: new HttpHeaders({
                    'Content-Type': 'application/json'
                })
            }).subscribe((authResult: { accessToken: string, refreshToken: string }) => {
                // update the stored tokens
                localStorage.setItem(this.ACCESS_TOKEN_KEY, authResult.accessToken);
                localStorage.setItem(this.REFRESH_TOKEN_KEY, authResult.refreshToken);
                const newTokenObject = this.parseAccessToken(authResult.accessToken);
                // resolve with the updated token for use ether in the init function or auth interceptor
                resolve(authResult.accessToken);
            }, error => {
                this.clearStoredData();
                this.userSubject.next(undefined);
                reject(error);
            });
        });
    }
 

Кто-нибудь видит причину, по которой это не должно сработать? (И, в частности, не должен работать в Safari против chrome, где он, похоже, работает должным образом)