如何捕获Request上的错误,然后打开一个模态,然后在modal用RxJS关闭时重试 [英] How to catch an error on a Request, then open a modal, then retry when modal closes with RxJS

查看:125
本文介绍了如何捕获Request上的错误,然后打开一个模态,然后在modal用RxJS关闭时重试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想调用可以使用Angular2的HTTP类返回授权失败(401)的服务器。

I want to make a call to a server that can return an authorization fail (401) with Angular2's HTTP class.

请求流应该看起来像那样:

The flow of the request should look like that:


  • 用户使用myService.getSomething()向服务器发出请求.subsubbe()

  • 如果服务器返回401:打开模态窗口询问用户他的凭据。

  • 用户成功登录到应用程序

  • 模态关闭并执行回调

  • 回调应该重试初始请求(myService.getSomething()。subscribe())

  • The user makes a request to the server with myService.getSomething().subscribe()
  • If the server returns a 401: open a modal window asking the user for his credentials.
  • The user successfully log back into the application
  • The modal closes and executes a callback
  • The callback should retry the initial request (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)=> ....)

doSomething() is used like that: doSomething().map((r) => r.json()).subscribe((r) => ....)

更新1

我将代码修改为@Thierry Templier的解决方案。

I modified my code to look like @Thierry Templier's solution.

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()函数)发送垃圾邮件。

Sadly it still doesn't work. The retryWhen is executed right away and doesn't wait for closedSubject.next() to be called. Therefore it starts an infinite loop, spamming the original Observable (the getSomething() function).

更新2

我创建了一个用于演示无限循环的plunker:

I created a plunker to demonstrate the infinite loop:

https://plnkr.co/edit/8SzmZlRHvi00OIdA7Bga

警告:运行plunker会使用字符串'test'向控制台发送垃圾邮件'

Warning: running the plunker will spam your console with the string 'test'

更新3

按照Thierry的正确答案,我试图找到一个不使用源字段的方法,因为它受到保护。在询问rxjs的问题跟踪器以使该字段公开后,贡献者回复了更好的解决方案。

Following Thierry's correct answer, I tried to find a way to not use the source field since it is protected. After asking on rxjs's issue tracker to make the field public, a contributor replied with a better solution.

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所以我不必使用源字段。

I avoid using .catch so I don't have to use the source field.

推荐答案

我认为即使在401错误的情况下你也需要返回一个可观察的东西:

I think that you need to return something an observable even in the case of the 401 error:

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

See this article for more details: https://jaxenter.com/reactive-programming-http-and-angular-2-124560.html.

修改

问题是 catch 回调的第二个参数不是源可观察对象。此source observable对应于其 source 属性的值:

The problem is that the second parameter of the catch callback isn't the source observable. This source observable corresponds to the value of its source property:

return ob.source.retryWhen((errors) => closedSubject);

查看工作插件: https://plnkr.co/edit/eb2UdF9PSMhf4Dau2hqe?p=preview

这篇关于如何捕获Request上的错误,然后打开一个模态,然后在modal用RxJS关闭时重试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆