如何通过对话框拦截未经授权的响应以输入密码并重试?
How do I intercept an unauthorised response with a dialog to enter a password and retry it?
我正在构建一个应用程序,该应用程序的后端具有简单的身份验证和 GET
请求。我想向用户显示一个对话框,让他们在身份验证过期时重新输入密码。当您填写密码并点击提交时,我想重试原来的 HTTP 调用并获取原始 Observable
内的数据。我猜这是可能的,但我似乎无法找到开始的方法。
这个问题类似:
但我正在使用 .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()));
}
}
此代码按原样工作,但在我输入密码并重新验证时不会重试调用。
我明白了。通过使用 .flatMap()
,我可以 link 一个 Observable
紧接着另一个 Observable
。这意味着 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();
});
};
}
对话框关闭后,returns 重试源 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,它将:
- 获取测试
- 如果失败,显示密码对话框以重新连接
- 对话完成后(这意味着我 re-authenticated),重试 HTTP 调用
我正在构建一个应用程序,该应用程序的后端具有简单的身份验证和 GET
请求。我想向用户显示一个对话框,让他们在身份验证过期时重新输入密码。当您填写密码并点击提交时,我想重试原来的 HTTP 调用并获取原始 Observable
内的数据。我猜这是可能的,但我似乎无法找到开始的方法。
这个问题类似:
但我正在使用 .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()));
}
}
此代码按原样工作,但在我输入密码并重新验证时不会重试调用。
我明白了。通过使用 .flatMap()
,我可以 link 一个 Observable
紧接着另一个 Observable
。这意味着 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();
});
};
}
对话框关闭后,returns 重试源 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,它将:
- 获取测试
- 如果失败,显示密码对话框以重新连接
- 对话完成后(这意味着我 re-authenticated),重试 HTTP 调用