我想使用 Angular2 的 HTTP 类调用可以返回授权失败(401)的服务器。
请求的流程应如下所示:
- 用户使用 myService.getSomething().subscribe() 向服务器发出请求
- 如果服务器返回 401:打开一个模式窗口,询问用户他的凭据。
- 用户成功登录回应用程序
- 模态关闭并执行回调
- 回调应该重试初始请求 (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
按照蒂埃里的正确答案,我试图找到一种不使用源字段的方法,因为它受到保护。在询问 rxjs 的问题跟踪器以公开该字段后,一位贡献者回复了一个更好的解决方案。
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 所以我不必使用源字段。