Angular HttpInterceptor: как использовать RxJS для нескольких условий - PullRequest
0 голосов
/ 17 октября 2018

Вот AuthInterceptor:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authService: AuthService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

        const Token = this.authService.getToken();

        if (!Token) {
            return next.handle(req);
        }
 
        // Refresh Token first
        if (Token.expiresRefreshToken && Number(Token.expiresRefreshToken) < Date.now()) {
            this.authService.refreshTokenRefresh(Token.tokenref)
            .subscribe((response) => {
                localStorage.setItem('tokenref', response.tokenref);
                localStorage.setItem('tokenrefexp', response.tokenrefexp);
            });
        }
        // Then next Access Token
        if (Token.expiresToken && Number(Token.expiresToken) < Date.now()) {
            this.authService.refreshToken(Token.tokenref)
            .subscribe((response) => {
                localStorage.setItem('token', response.token);
                localStorage.setItem('tokenexp', response.tokenexp);
            });
        }
        // Original request with updated custom headers
        return next.handle(req.clone({
            headers: req.headers
            .set('Authorization', 'Bearer ' + localStorage.getItem('token'))
            .set('X-Auth-Provider', localStorage.getItem('provider'))
        }));
    }

}

Мне нужно оценить эти условия перед отправкой запроса, потому что некоторые пользовательские заголовки могут измениться после методов refreshToken и refreshTokenRefresh.Есть ли способ оценить все внутри оператора RxJS?Первое условие (refreshTokenRefresh), затем второе (refreshToken) и, наконец, req.

Обновление: я получаю эту ошибку: RangeError: Maximum call stack size exceeded. Как это исправить?

1 Ответ

0 голосов
/ 17 октября 2018

Мы хотим дождаться завершения некоторых запросов (оценить заказ не имеет значения?), Чем другой запрос.

const queue = this.handleRefreshToke(this.handleRefreshTokenRefresh([])); - разместите там все запросы, которые должны быть выполнены до того, как мы позвоним next.handle.Используйте forkJoin, чтобы дождаться завершения всех запросов (помещенных в очередь), а затем сопоставьте их с другим Obervable (mergeMap).

PS Мы также можем переместить handleRefreshTokenRefresh и handleRefreshToke в отдельный HttpInterceptor.

EDITED Чтобы предотвратить рекурсивный вызов перехватчиков, мы должны пропустить перехватчики для вызова refreshTokens.

export const InterceptorSkipHeader = 'X-Skip-Interceptor';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authService: AuthService) { }

    handleRefreshTokenRefresh(queue: Observable<void>[]) {
        const Token = this.authService.getToken();
        if (Token.expiresRefreshToken && 
            const req = this.authService.refreshTokenRefresh(Token.tokenref)
              .pipe(tap((response) => {
                localStorage.setItem('tokenref', response.tokenref);
                localStorage.setItem('tokenrefexp', response.tokenrefexp);
            }));
            return [...queue, req];
        }
        return queue;
    }

    handleRefreshToke(queue: Observable<void>[]) {
        const Token = this.authService.getToken();
        if (Token.expiresToken && Number(Token.expiresToken) < Date.now()) {
            const req = this.authService.refreshToken(Token.tokenref)
              .subscribe((response) => {
                localStorage.setItem('token', response.token);
                localStorage.setItem('tokenexp', response.tokenexp);
            });
            return [...queue, req];
        }
        return queue;
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
       if (req.headers.has(InterceptorSkipHeader)) {
            const headers = req.headers.delete(InterceptorSkipHeader);
            return next.handle(req.clone({ headers }));
        }

        const Token = this.authService.getToken();

        if (!Token) {
            return next.handle(req);
        }

        const queue = this.handleRefreshToke(this.handleRefreshTokenRefresh([]));

        return forkJoin(queue).pipe(
            mergeMap(()=>{
                return next.handle(req.clone({
                    headers: req.headers
                        .set('Authorization', 'Bearer ' + localStorage.getItem('token'))
                        .set('X-Auth-Provider', localStorage.getItem('provider')),
                }));
            })
        );
    }

}

Добавить InterceptorSkipHeader для refreshTokens дляпропустить перехватчики.

// AuthService

refreshTokenRefresh(token){
   const headers = new HttpHeaders().set(InterceptorSkipHeader, '');
   return this.httpClient
    .get(someUrl, { headers })
}

refreshToken(token){
   const headers = new HttpHeaders().set(InterceptorSkipHeader, '');
   return this.httpClient
    .get(someUrl, { headers })
}
...