首页 > 解决方案 > 如何使用 rxjs 重试并在此之后执行函数

问题描述

我想重试一个 api 调用 10 次(等待一秒钟,因为它失败直到下一次执行),如果这 10 次失败,那么我将执行一个函数,这是我的方法:

private handleError(error, req: HttpRequest<any>, next: HttpHandler): Observable<any> {
  if (error.status === 0) {
    return next.handle(req).pipe(
      catchError(err => timer(1000).pipe(switchMapTo(this.checkConnection(err)))),
      retry(10)
    );
  } 
}

private checkConnection(error): Observable<any> {
   console.log(error)      
   return EMPTY;
}

这不起作用,通过使用提供的有关在重试和捕获错误之间切换顺序的解决方案,计时器停止工作。

我也尝试过 retryWhen:

if (error.status === 0) {
  return next.handle(req).pipe(
    retryWhen(errors => errors.pipe(delay(1000), take(10), 
    concatMapTo(this.checkConnection(errors)))));
}

然后我的问题只重试一次,我的“checkConnection”函数中没有原始错误

通过使用控制台日志,我可以看到这是任何尝试都会执行的,而我想要得到的是执行 10 次后执行。

我不知道怎么做。

我正在使用角度 8。

根据提供的答案,我的代码应该可以工作,但它没有,它有一个编译错误,这是我的全部服务:

import { throwError,  Observable , EMPTY } from 'rxjs';
import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { catchError, delay, retryWhen, take, concatMap } from 'rxjs/operators';

import { Router } from '@angular/router';


@Injectable()
export class HttpErrorInterceptorService implements HttpInterceptor {

  private handleError(error, req: HttpRequest<any>, next: HttpHandler): Observable<any> {
   if (error.status === 401) {
     this.router.navigate(['/login']);
     return EMPTY;  // Stops processing
   } else if (error.status === 403) {
     this.router.navigate(['/unauthorized']);
     return EMPTY;  // Stops processing
   }  else if (error.status === 0) {
      return next.handle(req).pipe(
        retryWhen((errors) => {
          return errors.pipe(
            delay(1000),
            take(10), // Number of retries
            concatMap(throwError)// Let the error bubble up again
          );
        }),
        catchError((err) => this.checkConnection(err)));
    }
   return throwError(error);
 }

 private checkConnection(error): Observable<any> {
   //it will have more logic in future, this is just the starting point to this function
   console.log(error)      
   return EMPTY;
 }

 constructor(private router: Router) {
 }

 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
   return next.handle(req).pipe(
     catchError((error) => this.handleError(error, req, next))
   );
 }

}

编译错误是

'(error: any, scheduler?: SchedulerLike) => Observable' 类型的参数不可分配给'(value: any, index: number) => Observable' 类型的参数。参数 'scheduler' 和 'index' 的类型不兼容。类型“编号”不可分配给类型“SchedulerLike”。

标签: angularangular8

解决方案


retry应该准确地捕捉到内部错误 N 次。第 N+1 次它会按预期传递。当前,您捕获每个错误并将其通过管道传输到checkConnection. 基本上切换retry并且catchError在您的原始示例中应该已经完成​​了这项工作。

    import {Observable, throwError, EMPTY} from 'rxjs';
    import {concatMap, delay, retryWhen, take} from 'rxjs/operators';

    private handleError(error, req: HttpRequest<any>, next: HttpHandler): Observable<any> {
      if (error.status === 0) {
        return next.handle(req).pipe(
          retryWhen((errors) => {
            return errors.pipe(
              delay(1000),
              take(10), // Number of retries
              concatMap(throwError), // Let the error bubble up again
            )
          ),
          catchError((err) => this.checkConnection(err))),
        );
      } 
    }

    private checkConnection(error): Observable<any> {
       console.log(error)      
       return EMPTY;
    }

推荐阅读