Используйте обещание в Angular HttpClient Interceptor

Могу ли я использовать обещание в пределах HttpInterceptor? Например:

export class AuthInterceptor implements HttpInterceptor{
this.someService.someFunction()
    .then((data)=>{
       //do something with data and then
       return next.handle(req);
    });
}

зачем мне это нужно? потому что мне нужно получить токен для добавления в заголовок запроса, прежде чем делать запрос на сервер.

Мой перехватчик:

@Injectable()
export class AuthInterceptor implements HttpInterceptor{

    constructor(private authService: AuthService){}

    intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
        console.log('Intercepted!');
        // return next.handle(req);
        this.authService.getToken()
            .then((token)=>{
                console.log(token);
                const reqClone = req.clone({
                    headers: req.headers
                            .set('Authorization', 'Bearer ' + token)
                            .append('Content-Type', 'application/json')
                });
                console.log(reqClone);
                return next.handle(reqClone);
            })
            .catch((err)=>{
                console.log('error in interceptor' + err);
                return null;
            });
    }
}

Запрос:

this.http.post(this.baseURL + 'hero', data)
                    .subscribe(
                            (res: any) => {
                                console.log('Saved Successfully.');
                                console.log(res);
                            },
                            (err: any) => {
                                console.log('Save Error.' + err);
                            }
                        );

Проблемы, с которыми я сталкиваюсь:

-> Я получаю эту ошибку до того, как обещание будет разрешено.

You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

Promise resloves и я получаю свой токен, но после ошибки.


person nightElf91    schedule 31.08.2017    source источник
comment
Я только что проверил свои запросы xhr в инструментах разработчика, там нет запроса «героя». Итак, перехватчик не продолжает запрос?   -  person nightElf91    schedule 31.08.2017


Ответы (3)


ОБНОВЛЕНИЕ: использование [email protected]

import { from, Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

    constructor(private authService: AuthService){}

    intercept(request: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
        return from(this.authService.getToken())
              .pipe(
                switchMap(token => {
                   const headers = request.headers
                            .set('Authorization', 'Bearer ' + token)
                            .append('Content-Type', 'application/json');
                   const requestClone = request.clone({
                     headers 
                    });
                  return next.handle(requestClone);
                })
               );
    }
}

ИСХОДНЫЙ ОТВЕТ

Да, вы можете внедрить требуемый сервис в метод конструктора перехватчика, а в реализации intercept получить значение, создать новый обновленный http-запрос и обработать его.

Я плохо разбираюсь в обещаниях, поэтому вы можете попробовать следующее:

import { fromPromise } from 'rxjs/observable/fromPromise';

@Injectable()
export class AuthInterceptor implements HttpInterceptor{

    constructor(private authService: AuthService){}

    intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
        return fromPromise(this.authService.getToken())
              .switchMap(token => {
                   const headers = req.headers
                            .set('Authorization', 'Bearer ' + token)
                            .append('Content-Type', 'application/json');
                   const reqClone = req.clone({
                     headers 
                    });
                  return next.handle(reqClone);
             });
    }
}
person Jota.Toledo    schedule 31.08.2017
comment
Спасибо, бро. Я обновил вопрос. надеюсь, теперь стало понятнее. - person nightElf91; 31.08.2017
comment
Это работает. Большое спасибо. это не сработало, потому что getToken() возвращает ненаблюдаемое обещание? @Хота.Толедо - person nightElf91; 31.08.2017
comment
Возвращаемый тип перехвата должен быть наблюдаемым, я сейчас не знаю, как работать с обещаниями, поэтому я преобразовал обещание в наблюдаемое и применил к нему операции. Я предполагаю, что ваша реализация не возвращала наблюдаемое. Если мой ответ помог вам, выберите его как ответ, чтобы ваш вопрос был отмечен как решенный :) - person Jota.Toledo; 31.08.2017
comment
Да, я изменил свою функцию на наблюдаемую, и теперь она работает без fromPromise. - person nightElf91; 31.08.2017
comment
Отлично, придерживайтесь наблюдаемых; они могут делать все, что обещано, и даже больше :) - person Jota.Toledo; 31.08.2017
comment
@ Jota.Toledo Могу я спросить, почему вы используете здесь switchMap? Насколько я понимаю, getToken преобразуется в наблюдаемое, но что такого особенного в получении токена аутентификации, который может заставить его отправлять более одного наблюдаемого значения? - person Jeffrey Wen; 22.05.2020
comment
@JeffreyWen, вы можете заменить его на mergeMap. Нет необходимости исключительно использовать switchMap по указанной вами причине :) - person Jota.Toledo; 22.05.2020
comment
@Jota.Toledo Я все еще относительно новичок в реактивном программировании, но зачем нам использовать такие вещи, как switchMap, mergeMap, concatMap и т. д., для чего-то такого простого, как получение токена аутентификации (возможно, из локального хранилища?). Является ли полностью отказ от switchMap/mergeMap жизнеспособным решением? - person Jeffrey Wen; 22.05.2020
comment
@JeffreyWen они необходимы для сопоставления токена с внутренним наблюдаемым (результатом next.handle). Идея состоит в том, чтобы в основном сопоставить поток токенов (всего с 1 событием) в новый. Из-за сигнатуры метода не существует жизнеспособных подходов без использования любого из упомянутых операторов. - person Jota.Toledo; 23.05.2020
comment
@Jota.Toledo Спасибо, что разъяснили это! - person Jeffrey Wen; 24.05.2020
comment
Обратите внимание: вы не увидите заголовки, добавленные в ваш запрос на клонирование, в вашем перехватчике из-за ленивой настройки заголовков. Они не будут материализованы до тех пор, пока не будет запущен последний обработчик. Я преследовал свой хвост, задаваясь вопросом, почему я не мог видеть свой заголовок авторизации. Я проследил до углового источника и понял это. - person Don; 20.10.2020

для RxJS 6+ я обновил ответ Jota.Toledo:

import { fromPromise } from 'rxjs/observable/fromPromise';

@Injectable()
export class AuthInterceptor implements HttpInterceptor{
constructor(private authService: AuthService){}
intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
    return fromPromise(this.authService.getToken())
          .pipe(switchMap(token => {
               const headers = req.headers
                        .set('Authorization', 'Bearer ' + token)
                        .append('Content-Type', 'application/json');
               const reqClone = req.clone({
                 headers 
                });
              return next.handle(reqClone);
         }));
 }  
}
person Capripio    schedule 25.05.2018
comment
Спасибо большое, сработало хорошо. Я пробовал другие решения, но ни одно из них не работало с Angular 6+. - person Ângelo Polotto; 29.06.2018

Моя очередь (спасибо Jota.Toledo и Capripio):

1) Переключите "fromPromise" на "из" --> fromPromise не существует на тип Наблюдаемый

2) Исправить кавычку «application/json»

import { Observable, from } from 'rxjs';
import { switchMap } from 'rxjs/operators';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor(private authService: AuthService){}

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

      return from(this.authService.getToken()).pipe(
        switchMap(token => {
            const headers = req.headers
                .set('Authorization', 'Bearer ' + token)
                .append('Content-Type', 'application/json');
            const reqClone = req.clone({
                headers
            });
            return next.handle(reqClone);
        }));
   }
}

Моя версия RxJs: "6.2.2" Надеюсь, это помогло!

person Echo    schedule 22.10.2018
comment
Почему мы используем switchMap после преобразования обещания в наблюдаемое? - person Richie50; 22.04.2021