как повторить попытку с помощью rx js и выполнить функцию после этого - PullRequest
0 голосов
/ 13 июля 2020

Я хочу повторить вызов 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 раз.

Я не могу найти, как это сделать.

Я использую angular 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' есть не назначается параметру типа '(значение: любое, индекс: число) => Наблюдаемый'. Типы параметров «планировщик» и «индекс» несовместимы. Тип 'number' не может быть назначен типу 'SchedulerLike'.

Ответы [ 2 ]

3 голосов
/ 13 июля 2020

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;
    }
0 голосов
/ 13 июля 2020

Кажется, вы попали в кроличью нору. Вы можете попробовать использовать оператор повторения , поскольку он предназначен для выполнения именно того, что вы пытаетесь сделать.


// RxJS v6+
import { repeat, delay } from 'rxjs/operators';

const delayedThing = yourObservable.pipe(delay(2000));

delayedThing
  .pipe(repeat(3))
  // delayed value...delayed value...delayed value
  .subscribe(console.log);
...