Javascript 如何捕获请求中的错误,然后打开一个模式,然后在使用RxJS关闭模式时重试
我想调用一个服务器,该服务器可以使用Angular2的HTTP类返回授权失败(401) 请求流应该如下所示:Javascript 如何捕获请求中的错误,然后打开一个模式,然后在使用RxJS关闭模式时重试,javascript,typescript,angular,rxjs,rxjs5,Javascript,Typescript,Angular,Rxjs,Rxjs5,我想调用一个服务器,该服务器可以使用Angular2的HTTP类返回授权失败(401) 请求流应该如下所示: 用户使用myService.getSomething().subscribe()向服务器发出请求 如果服务器返回401:则打开一个模式窗口,询问用户的凭据 用户已成功登录回应用程序 模态关闭并执行回调 回调应该重试初始请求(myService.getSomething().subscribe()) 以下是我目前的情况: export class MyService { //
- 用户使用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());
}
}
}
遗憾的是,它仍然不起作用。retryWhen立即执行,不等待调用closedSubject.next()。因此,它启动一个无限循环,对原始的可观察对象(getSomething()函数)进行垃圾处理
更新2
我创建了一个plunker来演示无限循环:
警告:运行plunker将向控制台发送带有字符串“test”的垃圾邮件
更新3
按照Thierry的正确答案,我试图找到一种不使用源字段的方法,因为它是受保护的。在要求rxjs的问题跟踪者公开该领域后,一位投稿人给出了更好的解决方案
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());
}
}
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());
}
});
}
公共获取(url:string,options?:RequestOptionsArgs):可观察{
返回super.get(url,options).retryWhen((errors:any)=>this.errorHandler(errors));
}
私有errorHandler(错误):任何{
返回错误。开关映射((错误)=>{
如果(错误状态===401){
让closedSubject=新主题();
this.modalService.open(新ModalConfig({
内容:LoginModalComponent,
close:()=>{closedSubject.next(err);}
}));
返回关闭的主题;
}
否则{
返回Observable.throw(err.json());
}
});
}
我避免使用.catch,因此我不必使用源字段。我想
retryWhen
应该会有所帮助。我认为即使在401错误的情况下,您也需要返回一些可观察的内容:
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());
}
}
请参阅工作说明:。我相信解决方案已经有了一些变化,因为在Angular的新闻版本中,我们必须使用
pipe()
方法。因此,我决定使用自定义运算符解决方案。一件好事是handleError()
方法可以作为全局函数导出,然后在多个服务中使用
有关详细信息,请参阅此解决方案:
导出类MyService{
// ...
public getSomething():可观察{
返回this.http.get(url,options).pipe(this.handleError('可能是您的自定义消息在这里');
}
私有句柄错误(错误消息:字符串){
返回(源:可观察)=>source.pipe(
retryWhen(errors=>errors.pipe(
合并映射((errorResponse:HttpErrorResponse)=>{
控制台错误(错误消息);
if(errorResponse.status==401){
const closedSubject=新主题();
this.modalService.open(新ModalConfig({
内容:LoginModalComponent,
关闭:()=>{
closedSubject.next();
}
}));
返回关闭的主题;
}
返回投掷器(错误响应);
})
))
);
}
}我觉得这接近答案,但仍然不起作用。当服务器抛出401时,errorHandler进入无限循环。它会在不等待模式关闭的情况下重试请求。我不知道您在登录模式中做了什么,但我想您需要在再次执行请求之前在请求中设置一些内容。出于这个原因,我认为您不应该使用retry,而应该根据请求的url和更新的选项(例如,
授权
头)再次执行请求。问题是retryWhen立即得到解决。它不是在等待调用closeSubject.next()。奇怪。不应该。也就是说我的代码片段中有一个输入错误。我相应地更新了我的答案…请参阅我的“编辑”部分和plunkr:。那么现在一切都正常了吗?
return ob.source.retryWhen((errors) => closedSubject);
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);
})
))
);
}