Как перехватить неавторизованный ответ с помощью диалогового окна, чтобы ввести пароль и повторить попытку?
Я создаю приложение, которое имеет бэкэнд с простой аутентификацией и GET
запрос. Я хочу показать пользователю диалоговое окно для повторного ввода пароля после истечения срока его аутентификации. Когда вы вводите свой пароль и нажимаете кнопку Отправить, я хочу повторить исходный HTTP-вызов и получить данные в исходном Observable
, Я предполагаю, что это возможно, но я не могу найти способ начать.
Этот вопрос похож: RxJS ждет второй наблюдаемой, а затем повторяет исходную наблюдаемую ошибку - TypeScript/Angular 2
Но я пользуюсь .pipe()
а также catchError
так что я могу подписаться на функцию в своем сервисе API вместо отдельного вызова HTTP. Я не уверен, какую другую информацию я должен предоставить, чтобы прояснить мой вопрос, но, пожалуйста, дайте мне знать, если вам нужно что-то еще знать.
Это мой текущий код:
import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { environment } from "../environments/environment";
import { Observable, ObservableInput } from "rxjs/Observable";
import { catchError, tap } from "rxjs/Operators";
import { MatDialog } from "@angular/material/dialog";
import { SessionExpiredComponent } from "./dialogs/session-expired/session-expired.component";
import "rxjs/add/observable/throw";
import { User } from "./classes/user";
import { Test } from "./classes/test";
const header = {
withCredentials: true
};
@Injectable()
export class ApiService {
user: User = null || JSON.parse(localStorage.getItem("user"));
constructor(private http: HttpClient, private matDialog: MatDialog) {}
private errorHandler() {
return (err: any) => {
let dialog = this.matDialog.open(SessionExpiredComponent, {
data: { err: err, email: this.user.email, apiService: this },
});
return dialog.afterClosed();
//I want to return a retry of the original observable
};
}
login(email: string, password: string): void {
const formHeader = {
headers: new HttpHeaders({
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
}),
withCredentials: true
};
this.http
.post<User>(
environment.backend + "auth/login",
"email=" +
encodeURIComponent(email) +
"&password=" +
encodeURIComponent(password),
formHeader
)
.subscribe(user => {
this.user = user;
localStorage.setItem("user", JSON.stringify(user));
});
}
getTests(): Observable<any> {
return this.http
.get<any>(
environment.backend +
"tests/query?accountId=" +
this.user.defaultAccount,
header
)
.pipe(catchError(this.errorHandler()));
}
}
Этот код работает как есть, но не повторяет вызов при вводе пароля и повторной аутентификации.
1 ответ
Я понял. Я могу связать Observable
непосредственно за другим Observable
используя .flatMap()
, Это означает, что errorHandler
выглядит так:
private errorHandler(source: Observable<any>) {
return (err: any) => {
let dialog = this.matDialog.open(SessionExpiredComponent, {
data: { err: err, email: this.user.email, apiService: this }
});
return dialog.afterClosed().flatMap(data => {
return source.retry();
});
};
}
После закрытия диалогового окна возвращается повторная попытка источника Observable
, который мне нужно передать в errorHandler
как это:
getTests(): Observable<any> {
let observable = this.http
.get<any>(
environment.backend +
"tests/query?accountId=" +
this.user.defaultAccount,
header
);
return observable.pipe(catchError(this.errorHandler(observable)));
}
А теперь мой getTests
Функция является наблюдаемой, которая будет:
- Получить тесты
- Если это не удается, покажите диалоговое окно пароля для повторного подключения
- Когда диалоговое окно завершено (что означает, что я повторно аутентифицировался), повторите попытку HTTP