在Angular 2+;中订阅后API调用失败时如何重试;

在Angular 2+;中订阅后API调用失败时如何重试;,angular,rxjs,interceptor,angular-httpclient,retrywhen,Angular,Rxjs,Interceptor,Angular Httpclient,Retrywhen,我正在调用API以获取随机详细信息。问题是,有时我得到502错误作为坏网关,它也可能由于坏的网络连接而中断。 下面是我的API调用代码 // COMPONENT API CALL SUBSCRIBE this._service.post('randomAPI/getdetails', filters).subscribe((response: any) => { this.itemList = response; }); // SHARED SERVIC

我正在调用API以获取随机详细信息。问题是,有时我得到502错误作为坏网关,它也可能由于坏的网络连接而中断。 下面是我的API调用代码

// COMPONENT API CALL SUBSCRIBE
     this._service.post('randomAPI/getdetails', filters).subscribe((response: any) => {
     this.itemList = response;    
   });

// SHARED SERVICE
     post<T>(url: string, body: any): Observable<T> {
     return this.httpClient.post<T>(url, body);
   } 
//组件API调用订阅
此._service.post('randomAPI/getdetails',filters.).subscribe((响应:any)=>{
this.itemList=响应;
});
//共享服务
post(url:string,body:any):可观察{
返回此.httpClient.post(url,正文);
} 
每当我收到500或502服务器错误时,使用拦截器我将路由到一个错误页面,以通知用户服务器问题

相反,如果API失败,我可以让它在组件级或拦截器级再试一次,然后路由到错误页面吗

// INTERCEPTOR
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(catchError(error => {
        if (error.status === 401 || error.status === 400 || error.status === 403) {
            this.router.navigateByUrl('abort-access', { replaceUrl: true });
        } else if (error.status === 500 || error.status === 502) {
                this.router.navigateByUrl('server-error', { replaceUrl: true });
        }
        return throwError("error occured");
     }));
    }
//拦截器
拦截(请求:HttpRequest,下一步:HttpHandler):可观察{
返回next.handle(request).pipe(catchError)(error=>{
如果(error.status==401 | | error.status==400 | | | error.status==403){
this.router.navigateByUrl('abort-access',{replaceUrl:true});
}else if(error.status==500 | | error.status==502){
this.router.navigateByUrl('server-error',{replaceUrl:true});
}
返回投掷器(“发生错误”);
}));
}
我看到了一些示例,因为它们使用管道并添加retryWhen()来实现这一点。但是,由于我是一个非常新的角度,我不能想出一个方法来做到这一点


有人能帮忙吗?

您可以使用
retryWhen
操作员。这背后的原理是当您不想重试时抛出错误

retryWhen
实际上是一种奇特的
catchError
,除非抛出错误,否则它将自动重试

拦截(请求:HttpRequest

限制重试次数 这样做的危险在于,您将执行连续的请求,直到服务器不返回500或502。在现实世界的应用程序中,您可能希望限制重试次数,并且可能会在其中设置某种延迟,以避免请求淹没服务器

为此,您可以使用
take(n)
将请求限制为
n
失败的尝试。这对您不起作用,因为
take
将阻止可观察对象进入
catchError
,并且您将无法执行导航

相反,您可以设置重试限制,并在达到重试限制后抛出错误

const retryLimit=3;
设尝试=0;
拦截(请求:HttpRequest)执行此功能

           delayedRetry(delayMs:number,maxRetry:number){

            let retries=maxRetry;

            return (src:Observable<any>)=>
            src.pipe(
           retryWhen((errors:Observable<any>)=>errors.pipe(
           delay(delayMs),
           mergeMap(error =>retries -- > 0 ? 
           of(error):throwError("Retrying..."))
     ))
   )
  
}
delayedRetry(delayMs:number,maxRetry:number){
让retries=maxRetry;
回报率(src:可观察)=>
钢骨混凝土管(
retryWhen((错误:可观察)=>errors.pipe(
延迟(延迟毫秒),
合并映射(错误=>重试-->0?
of(错误):投掷者(“重试…”)
))
)
}
在api url中调用此函数

    return this.http.get<RouteData[]>(url).pipe(
    this.delayedRetry(10000,4),
    catchError(err => {
   console.error(err);
    return EMPTY;
    }),
  shareReplay()
  );
返回这个.http.get(url.pipe)(
这是延迟测光法(10000,4),
catchError(err=>{
控制台错误(err);
返回空;
}),
shareReplay()
);

您希望在什么条件下重试?只有当失败时,准确地说,主要是500和502错误状态时,当我们从组件调用API时,我们才能在订阅方法中使用retryWhen?否。在订阅之前在管道中发生时重试。您可以将管道添加到任何可观察的对象。
可观察的.pipe(map()).pipe(map()).pipe(retryWhen()).subscribe()
。因此,您的组件将执行类似于
的操作。service.makeRequest().pipe(retryWhen()).subscribe()
我有一个疑问-如果我编写这个.service.makeRequest().pipe(retryWhen()).subscribe((resp)=>{this.list=resp});,您的意思是说。在重试完成之前,不会为列表分配resp?是的。
retryWhen
会因为收到错误而发出另一个请求,因此无论如何都不会有列表可供使用。