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

问题描述 投票:1回答:1

我正在调用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);
   } 

每当出现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");
     }));
    }

我看到了一些使用管道并添加retryWhen()的示例。但是,由于我刚接触过棱角,因此无法找到一种方法。

有人可以帮忙吗?

angular rxjs interceptor angular-httpclient retrywhen
1个回答
2
投票

您可以使用retryWhen运算符。这背后的原理是,当您要重试时,会抛出错误。

[retryWhen实际上是精美的catchError,它将自动重试,除非抛出错误。

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  return next.handle(request).pipe(
    // retryWhen operator should come before catchError operator as it is more specific
    retryWhen(errors => errors.pipe(
      // inside the retryWhen, use a tap operator to throw an error 
      // if you don't want to retry
      tap(error => {
        if (error.status !== 500 && error.status !== 502) {
          throw error;
        }
      })
    )),

    // now catch all other errors
    catchError(error => {     
      if (error.status === 401 || error.status === 400 || error.status === 403) {
        this.router.navigateByUrl('abort-access', { replaceUrl: true });
      }

      return throwError("error occured");
    })
  );
}

DEMO:https://stackblitz.com/edit/angular-qyxpds

限制重试

这样做的危险是您将连续执行请求,直到服务器未返回500或502。在实际应用中,您希望限制重试次数,并可能在其中进行某种延迟以避免泛洪您的服务器的请求。

为此,您可以使用take(n),但是在n尝试失败后可以观察到,并且catchError操作员将无法执行导航。

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

const retryLimit = 3;
let attempt = 0;

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  return next.handle(request).pipe(
    // retryWhen operator should come before catchError operator as it is more specific
    retryWhen(errors => errors.pipe(
      tap(error => {
        // increment the attempt and check to see if we need to end the retry
        if (attempt++ >= retryLimit || (error.status !== 500 && error.status !== 502)) {
          throw error;
        }
      })  
    )),

    // now catch all other errors
    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 });
        // do not return the error
        return empty();
      }

      return throwError("error occured");
    })
  );
}

DEMO:https://stackblitz.com/edit/angular-ud1t7c

© www.soinside.com 2019 - 2024. All rights reserved.