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

Я создаю приложение, которое имеет бэкэнд с простой аутентификацией и 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
Другие вопросы по тегам