如何捕获请求错误,然后打开模态,然后在模态关闭时使用 RxJS 重试
How to catch an error on a Request, then open a modal, then retry when modal closes with RxJS
我想调用一个服务器,该服务器可以 return 使用 Angular2 的 HTTP class 授权失败 (401)。
请求的流程应该是这样的:
- 用户使用myService.getSomething().subscribe()
向服务器发出请求
- 如果服务器 return 出现 401:打开模式 window 询问用户的凭据。
- 用户成功登录回应用程序
- 模态关闭并执行回调
- 回调应该重试初始请求 (myService.getSomething().subscribe())
这是我目前拥有的:
export class MyService {
// ...
public getSomething(): Observable<Response> {
return this.http.get(url, options).catch((res: any, ob: any) => this.errorHandler(res, ob));
}
public errorHandler(res: Response, ob: Observable<any>): Observable<Response> {
if (res.status === 401) {
this.modalService.open(new ModalConfig({
content: LoginModalComponent,
close: () => { ob.retry(1); console.log("weow") } // <=close is the callback that should initiate the retry action on the initial request.
}));
}
else {
return Observable.throw(res.json());
}
}
}
doSomething() 是这样使用的:doSomething().map((r) => r.json()).subscribe((r) => ....)
更新 1
我修改了我的代码,使其看起来像@Thierry Templier 的解决方案。
private errorHandler(res: Response, ob: Observable<any>): Observable<Response> {
if (res.status === 401) {
let closedSubject = new Subject();
this.modalService.open(new ModalConfig({
content: LoginModalComponent,
close: () => { closedSubject.next(res);} // I also tried .complete(), .next(null), .next(true), .next(false)
}));
return ob.retryWhen(() => closedSubject);
}
else {
return Observable.throw(res.json());
}
}
遗憾的是它仍然不起作用。 retryWhen 立即执行,不会等待 closedSubject.next() 被调用。因此它开始一个无限循环,向原始 Observable 发送垃圾邮件(getSomething() 函数)。
更新 2
我创建了一个 plunker 来演示无限循环:
https://plnkr.co/edit/8SzmZlRHvi00OIdA7Bga
警告:运行 plunker 将使用字符串 'test'
向您的控制台发送垃圾邮件
更新 3
根据 Thierry 的正确答案,我试图找到一种不使用源字段的方法,因为它受到保护。在询问 rxjs 的问题跟踪器以创建字段 public 后,一位贡献者回复了一个更好的解决方案。
public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
return super.get(url, options).retryWhen((errors: any) => this.errorHandler(errors));
}
private errorHandler(errors): any {
return errors.switchMap((err) => {
if (err.status === 401) {
let closedSubject = new Subject();
this.modalService.open(new ModalConfig({
content: LoginModalComponent,
close: () => { closedSubject.next(err); }
}));
return <any>closedSubject;
}
else {
return Observable.throw(err.json());
}
});
}
我避免使用 .catch,所以我不必使用源字段。
我想 retryWhen
operator 应该有帮助。
我认为即使在 401 错误的情况下,您也需要 return 一些可观察的东西:
public errorHandler(res: Response, ob: Observable<any>): Observable<Response> {
if (res.status === 401) {
let closedSubject = new Subject();
this.modalService.open(new ModalConfig({
content: LoginModalComponent,
close: () => {
closedSubject.next();
}));
return ob.retryWhen(() => closedSubject);
}
else {
return Observable.throw(res.json());
}
}
有关详细信息,请参阅本文:https://jaxenter.com/reactive-programming-http-and-angular-2-124560.html。
编辑
问题是 catch
回调的第二个参数不是可观察的源。这个 source observable 对应于它的 source
属性:
的值
return ob.source.retryWhen((errors) => closedSubject);
查看工作插件:https://plnkr.co/edit/eb2UdF9PSMhf4Dau2hqe?p=preview。
我相信解决方案有所改变,因为在 Angular 的新闻版本中我们必须使用 pipe()
方法。所以我决定使用自定义操作员解决方案。一件好事是 handleError()
方法可以导出为全局函数,然后在多个服务中使用。
有关详细信息,请参阅此解决方案:https://blog.angularindepth.com/retry-failed-http-requests-in-angular-f5959d486294
export class MyService {
// ...
public getSomething(): Observable<Response> {
return this.http.get(url, options).pipe(this.handleError('Maybe your a custom message here'));
}
private handleError(errorMessage: string) {
return (source: Observable<any>) => source.pipe(
retryWhen(errors => errors.pipe(
mergeMap((errorResponse: HttpErrorResponse) => {
console.error(errorMessage);
if (errorResponse.status === 401) {
const closedSubject = new Subject();
this.modalService.open(new ModalConfig({
content: LoginModalComponent,
close: () => {
closedSubject.next();
}
}));
return closedSubject;
}
return throwError(errorResponse);
})
))
);
}
}
我想调用一个服务器,该服务器可以 return 使用 Angular2 的 HTTP class 授权失败 (401)。
请求的流程应该是这样的:
- 用户使用myService.getSomething().subscribe() 向服务器发出请求
- 如果服务器 return 出现 401:打开模式 window 询问用户的凭据。
- 用户成功登录回应用程序
- 模态关闭并执行回调
- 回调应该重试初始请求 (myService.getSomething().subscribe())
这是我目前拥有的:
export class MyService {
// ...
public getSomething(): Observable<Response> {
return this.http.get(url, options).catch((res: any, ob: any) => this.errorHandler(res, ob));
}
public errorHandler(res: Response, ob: Observable<any>): Observable<Response> {
if (res.status === 401) {
this.modalService.open(new ModalConfig({
content: LoginModalComponent,
close: () => { ob.retry(1); console.log("weow") } // <=close is the callback that should initiate the retry action on the initial request.
}));
}
else {
return Observable.throw(res.json());
}
}
}
doSomething() 是这样使用的:doSomething().map((r) => r.json()).subscribe((r) => ....)
更新 1
我修改了我的代码,使其看起来像@Thierry Templier 的解决方案。
private errorHandler(res: Response, ob: Observable<any>): Observable<Response> {
if (res.status === 401) {
let closedSubject = new Subject();
this.modalService.open(new ModalConfig({
content: LoginModalComponent,
close: () => { closedSubject.next(res);} // I also tried .complete(), .next(null), .next(true), .next(false)
}));
return ob.retryWhen(() => closedSubject);
}
else {
return Observable.throw(res.json());
}
}
遗憾的是它仍然不起作用。 retryWhen 立即执行,不会等待 closedSubject.next() 被调用。因此它开始一个无限循环,向原始 Observable 发送垃圾邮件(getSomething() 函数)。
更新 2
我创建了一个 plunker 来演示无限循环:
https://plnkr.co/edit/8SzmZlRHvi00OIdA7Bga
警告:运行 plunker 将使用字符串 'test'
向您的控制台发送垃圾邮件更新 3
根据 Thierry 的正确答案,我试图找到一种不使用源字段的方法,因为它受到保护。在询问 rxjs 的问题跟踪器以创建字段 public 后,一位贡献者回复了一个更好的解决方案。
public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
return super.get(url, options).retryWhen((errors: any) => this.errorHandler(errors));
}
private errorHandler(errors): any {
return errors.switchMap((err) => {
if (err.status === 401) {
let closedSubject = new Subject();
this.modalService.open(new ModalConfig({
content: LoginModalComponent,
close: () => { closedSubject.next(err); }
}));
return <any>closedSubject;
}
else {
return Observable.throw(err.json());
}
});
}
我避免使用 .catch,所以我不必使用源字段。
我想 retryWhen
operator 应该有帮助。
我认为即使在 401 错误的情况下,您也需要 return 一些可观察的东西:
public errorHandler(res: Response, ob: Observable<any>): Observable<Response> {
if (res.status === 401) {
let closedSubject = new Subject();
this.modalService.open(new ModalConfig({
content: LoginModalComponent,
close: () => {
closedSubject.next();
}));
return ob.retryWhen(() => closedSubject);
}
else {
return Observable.throw(res.json());
}
}
有关详细信息,请参阅本文:https://jaxenter.com/reactive-programming-http-and-angular-2-124560.html。
编辑
问题是 catch
回调的第二个参数不是可观察的源。这个 source observable 对应于它的 source
属性:
return ob.source.retryWhen((errors) => closedSubject);
查看工作插件:https://plnkr.co/edit/eb2UdF9PSMhf4Dau2hqe?p=preview。
我相信解决方案有所改变,因为在 Angular 的新闻版本中我们必须使用 pipe()
方法。所以我决定使用自定义操作员解决方案。一件好事是 handleError()
方法可以导出为全局函数,然后在多个服务中使用。
有关详细信息,请参阅此解决方案:https://blog.angularindepth.com/retry-failed-http-requests-in-angular-f5959d486294
export class MyService {
// ...
public getSomething(): Observable<Response> {
return this.http.get(url, options).pipe(this.handleError('Maybe your a custom message here'));
}
private handleError(errorMessage: string) {
return (source: Observable<any>) => source.pipe(
retryWhen(errors => errors.pipe(
mergeMap((errorResponse: HttpErrorResponse) => {
console.error(errorMessage);
if (errorResponse.status === 401) {
const closedSubject = new Subject();
this.modalService.open(new ModalConfig({
content: LoginModalComponent,
close: () => {
closedSubject.next();
}
}));
return closedSubject;
}
return throwError(errorResponse);
})
))
);
}
}