如何使用对话框截取未经授权的响应以输入密码并重试?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用对话框截取未经授权的响应以输入密码并重试?相关的知识,希望对你有一定的参考价值。

我正在构建一个应用程序,其后端具有简单的身份验证和GET请求。我想向用户显示一个对话框,在其身份验证到期时重新输入密码。当您填写密码并单击“提交”时,我想重试原始HTTP调用并获取原始Observable中的数据。我猜这是可能的,但我似乎无法找到一种方法开始。

这个问题类似:RxJS wait for second observable then retry original observable on error - 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()));
  }
}

此代码按原样运行,但在我输入密码并重新进行身份验证时不会重试该呼叫。

答案

我想到了。我可以通过使用ObservableObservable直接链接到另一个.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函数是一个Observable,它将:

  • 得到测试
  • 如果失败,请显示密码对话框以重新连接
  • 对话框完成后(这意味着我重新进行了身份验证),重试HTTP调用

以上是关于如何使用对话框截取未经授权的响应以输入密码并重试?的主要内容,如果未能解决你的问题,请参考以下文章

密码更新时出现未经授权的错误

在刷新身份验证令牌时处理多个未经授权的请求

SQLSERVER使用密码加密备份文件以防止未经授权还原数据库

当尝试注册用户以“未经授权”响应时

如何在 webflux 中实现自定义身份验证管理器时对未经授权的请求响应自定义 json 正文

如何在 Spring WebFlux 上自定义未经授权的响应