有点晚了,但这是新版本的 rxjs (>6) 的处理方法
我猜您正在尝试在发生故障时自动重试网络。
这可以通过不同的方式来实现,但这里是一个非常小的实现
RetryWhen() - 如果任何错误被 observable 抛出,THis 操作符会捕获并从中创建 errorObservable。
现在使用 errorObservable,我们可以针对特定失败集重试指定次数的尝试
例如,在 404 失败的情况下重试,确实没有必要,但在 500X 异常情况下,它确实是强制性的。
DelayWhen - 我们可以使用这个操作符来指定一个 timer observable,它会延迟下一次重试尝试,直到时间过去。这也提供了线性增加每次重试尝试之间的延迟的额外优势
iif - 使用此条件运算符确实使我们能够根据给定条件过滤和执行必要的 observable。您也可以在 stackoverflow 中举例。但我会给出一个简单的 if else 说明
contactMap - 这是高阶 observable 运算符,这意味着它产生 /maps 一个输入/observable 到一个输出 observable。使用它的原因是,我们需要重试重试操作以防相同的失败指定次数,并且重新启动操作的最佳方法是通过错误 Observable。
请注意,我们可以使用其他高阶可观察操作符,例如 mergeMap/switchMap——它们各有优缺点,但我更喜欢使用它。再次,contactMap 与 concat 运算符不同,因此此处应注意
我发现在 Angular 中实现这种重试的最佳位置是在 httpinterceptors 内部,但这也可以在服务内部完成
这是一个示例实现:
// Class to intercept all network calls and retry for X number of times
export class ErrorInterceptor implements HttpInterceptor {
// private authService: UserAuthenticationService;
private ngxLogger: NGXLogger;
private errorHandlerService: ErrorHandlerService;
constructor(injector: Injector) {
this.ngxLogger = injector.get(NGXLogger);
this.errorHandlerService = injector.get(ErrorHandlerService);
}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const interceptObs$ = next.handle(req);
// you could filter for the URLS that this should be applied like this
if (req.url.match(API_FETCH_TOKEN)) {
let retryAttempts = 0;
const httpInterceptor$ = interceptObs$.pipe(
retryWhen(errorObs => {
return errorObs.pipe(
tap(errval => console.log(`Retrying because of err:${errval}`)),
concatMap(errObsValue => {
if (
errObsValue instanceof HttpErrorResponse &&
errObsValue.status != 404
) {
console.log('inside concatMap', errObsValue);
if (retryAttempts > APP_NET_RETRIES) {
return throwError(this.getErrorModel(errObsValue, req));
} else {
retryAttempts++;
// this linearly increases the delay of attempts
delayWhen(() =>
timer(retryAttempts * APP_NET_RETRIES_DELAY * 1000)
);
return httpInterceptor$;
}
}
})
);
})
);
return httpInterceptor$;
} else {
return interceptObs$;
}
// above is the notifier observable, with errors captured as input observable
// so we could operate on this observable for retires
// also make sure to return the error observable - i.e the notifier observable
// reason being all errors should again be returned so as to capture them and
// only when they are returned they can be retried
// Also make sure after take() - no.of retries we just throw a last occuring error obs
}
// I like to create a custom error model and handle that in Custom ErrorHandler
// Below is the sample implementation I use. but again this is your preference
// you can just rethrow the error alone
async getErrorModel(errValue, req): Promise<ErrorModel> {
const errModel = new ErrorModel();
errModel.Error = errValue;
errModel.ErrorMessage = 'Error in retrieving the token:' + errValue.message;
errModel.ErrorStatus = 421;
errModel.ErrorUrl = req.url;
errModel.Timestamp = momentTimeZone
.tz(DEFAULT_TIME_ZONE)
.format(DEFAULT_TIME_ZONE);
await this.errorHandlerService.handleError(errModel);
return Promise.resolve(errModel);
}
}
希望对您有所帮助..
编辑:确实有一篇关于 backoff-rxjs 的好文章,它确实缩短了我们在上面所做的一切。请参考this link