Angular HttpInterceptor: как использовать RxJS для нескольких условий

Вот 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. Как это исправить?

Просто поместите последнюю часть кода в else и поместите next.handle в свои if.

Roberto Zvjerković 17.10.2018 09:16

Вы можете прочитать RxJS, где находится оператор If-Else?

SiddAjmera 17.10.2018 09:56
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
6
2
1 645
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

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

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

РЕДАКТИРОВАТЬ Чтобы предотвратить рекурсивный вызов перехватчиков, мы должны пропустить перехватчики для вызова 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 })
}

порядок оценки имеет значение, потому что мне нужен действующий токен обновления (первое условие) для создания токена доступа (второе условие).

James 17.10.2018 15:56

Вы можете использовать concat вместо forkJoin

Buggy 17.10.2018 17:13

вы можете подтвердить мой ответ? Я думаю, что что-то не так, потому что мой сервер немного нестабилен: много раз перезагружается при использовании перехватчика. Я получаю эту ошибку на консоли RangeError: Maximum call stack size exceeded.

James 17.10.2018 22:46

Вам нужно пропустить перехватчик для handleRefreshToken и handleRefreshTokenRefresh .

Buggy 18.10.2018 09:07

Спасибо! Раньше я пытался перестать вызывать перехватчик с HttpBackEnd, но это не сработало.

James 18.10.2018 16:01

Другие вопросы по теме