Использование обещания вернуть объект запроса от перехватчика HTTP

Я часами ломал голову над этим, и я надеюсь, что кто-то может мне помочь и направить меня. Итак, я разрабатываю модуль аутентификации приложений Angular 7. Одним из требований является разработка перехватчика HTTP для добавления токена авторизации (JWT), а также для обработки всех сообщений об ошибках.

Я использую пакет NPM для обработки локального хранилища токенов. Этот пакет использует методы set и get для хранения и возврата обещания, а не фактического значения токена.

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

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

    // Trying to get the token here but this returns a promise
    // this.token is a service for managing storage and retrieving of tokens
    const token = this.token.getToken();

    // If token is got, set it in the header
    // But when i console log, i see [object promise] other than the token
    if (token) {
        request = request.clone({
            headers: request.headers.set('Authorization', 'Bearer ' + token)
        });
    }

    return next.handle(request).pipe(catchError(err => {
        // Logs out the user if 401 error
        if (err.status === 401) {
            this.token.remove()
                .then(() => {
                    this.auth.changeAuthStatus(false);
                    this.router.navigateByUrl('/login');
                });
        }

        // Returns the error message for the user to see
        // for example in an alert
        const error = err.error.message || err.statusText;
        return throwError(error);
    }));
}

Надеюсь, я хорошо объяснил эту проблему. Я пытался использовать async перед функцией перехватчика, но получаю неприятную красную ошибку, говорящую TS1055: Type 'typeof Observable' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.   Types of parameters 'subscribe' and 'executor' are incompatible..

Буду признателен за любую помощь в решении этой проблемы.

Благодарю вас!


person realnsleo    schedule 21.02.2019    source источник
comment
вы сохранили токен в локальном хранилище?   -  person Zarna Borda    schedule 22.02.2019
comment
@ZarnaBorda На самом деле я использую ionic, и я хотел придерживаться пакета хранилища, который по умолчанию возвращает обещание. Мне удалось исправить это, используя приведенный ниже код заброшенного объекта.   -  person realnsleo    schedule 22.02.2019


Ответы (2)


чтобы включить асинхронную обработку в ваш перехватчик, вы хотите продвигать свое обещание к наблюдаемому и switchMap ваши наблюдаемые вместе, возвращая правильный запрос:

import { from as observableFrom } from "rxjs";
import { switchMap } from "rxjs/operators";

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return observableFrom(this.token.getToken()).pipe(
        switchMap(token => {

            // do something with your promise-returned token here

            return next.handle(request).pipe(catchError(err => {
                // Logs out the user if 401 error
                if (err.status === 401) {
                    this.token.remove()
                        .then(() => {
                            this.auth.changeAuthStatus(false);
                            this.router.navigateByUrl('/login');
                        });
                }

                // Returns the error message for the user to see
                // for example in an alert
                const error = err.error.message || err.statusText;
                return throwError(error);
            }));
        })
    );
}

не тестировал этот код напрямую, поэтому прошу прощения за любые опечатки, но он должен привести вас туда, куда вы хотите.

1) продвиньте свое обещание до наблюдаемого с помощью from

2) соедините свои наблюдаемые с switchMap

я заметил, что на самом деле вы не используете токен, возвращенный в вашем примере, вы бы сделали это в функции в switchMap, которая получает результат обещания

person derelict    schedule 22.02.2019
comment
Большое спасибо за это. В конце концов я провел еще несколько исследований о switchMap и обнаружил, что он может творить удивительные вещи. Все работает как положено! Я собирался отказаться от Promises и Observables. Ты заслуживаешь пива. Ваше здоровье! - person realnsleo; 22.02.2019
comment
@derelict Можете ли вы объяснить, почему switchMap вместо flatMap/mergeMap? Насколько я знаю, это даст тот же результат, если this.token.getToken() сработает только один раз, верно? Спасибо. - person sevenlops; 24.02.2021
comment
@sevenlops - это было давно. я думаю, что я думал о том, чтобы остановить дублирование http-запросов от каждого запрашивающего токена; я поднял свой пример из проекта, где это было соображением. поскольку должен быть только один ответ от обещания getToken(), любой из них будет одинаковым. - person derelict; 25.02.2021

Попробуйте взять токен напрямую из локального хранилища. Для этого, когда вы получаете токен, сохраните этот токен в локальном хранилище, используя метод службы токенов.

Попробуйте код ниже:

токен.service.ts

setToken(token) {
    localStorage.setItem('app-token', JSON.stringify(token));
}

getToken() {
    return JSON.parse(localStorage.getItem('app-token'));
}

Код перехватчика

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

//This token is retrieved from local storage
const token = this.token.getToken();

// If token is got, set it in the header
// But when i console log, i see [object promise] other than the token
if (token) {
    request = request.clone({
        headers: request.headers.set('Authorization', 'Bearer ' + token)
    });
}

return next.handle(request).pipe(catchError(err => {
    // Logs out the user if 401 error
    if (err.status === 401) {
        this.token.remove()
            .then(() => {
                this.auth.changeAuthStatus(false);
                this.router.navigateByUrl('/login');
            });
    }

    // Returns the error message for the user to see
    // for example in an alert
    const error = err.error.message || err.statusText;
    return throwError(error);
}));
}
person Zarna Borda    schedule 22.02.2019