gpt4 book ai didi

angular - NGRX:http 重试拦截器导致不触发失败操作

转载 作者:行者123 更新时间:2023-12-03 23:08:14 24 4
gpt4 key购买 nike

我正在使用 NGRX,我想要简单的 获取 对 API 的请求为 重试五次。原因是我正在使用 Azure Cosmos-DB,但有时会受到限制。 (免费层)。

我为此创建了一个 http-interceptor,它非常简单,看起来像这样

@Injectable()
export class HttpRetryInterceptor implements HttpInterceptor {
public intercept(
request: HttpRequest<any>,
httpHandler: HttpHandler
): Observable<HttpEvent<any>> {
const nextRequest = request.clone();

// here the NGRX failure action is not being triggered after five failing requests
return httpHandler.handle(nextRequest).pipe(
retryWhen(errors => errors.pipe(delay(1000), take(5))),
last()
);
}
}

这工作得很好,每个失败的 http 请求都会重试五次,延迟为 1000 毫秒。

现在的问题是,当请求实际失败五次时,效果中的失败操作没有被触发。
load$ = createEffect(() =>
this.actions$.pipe(
ofType(globalStatsActions.load),
mergeMap(() =>
this.globalStatsService.load().pipe(
map(stats =>
globalStatsActions.loaded({
latestStats: stats
})
),
catchError(() => of(globalStatsActions.loadFailed())) // not being called using the http-interceptor
)
)
)
);

奇怪的是,当 http-interceptor 使用运算符 retry而不是 retryWhen它工作得很好。遗憾的是,使用该运算符您无法定义 delay ,这在我的情况下是必需的。

另一个有趣的事实是,当在效果中使用的服务上使用相同的重试逻辑时,它工作得很好。
// here the failure action is being triggered after five failing requests
public load(): Observable<GlobalStats> {
return this.http.get<GlobalStats>(`${this.baseUrl}stats`)
.pipe(
retryWhen(errors => errors.pipe(delay(1000), take(5))),
last()
);

虽然这不是很多代码,并且可以复制到我正在使用的每个 http 服务上,但我更愿意使用拦截器来代替它。

我似乎找不到原因,我希望那里的任何人都知道为什么这不起作用。

最佳答案

Another interesting fact is, that when using the very same retry logic on the service used in the effect, it works just fine.


retry(n)将在 n 时简单地传递错误通知达到了尝试。当尝试 < n ,它将从源取消订阅,然后它将 重新订阅给它。
retryWhen(fn)维护一个内部订阅,它是函数 fn 提供的 observable 的结果. fn的单个参数是 错误主题 每次发生错误时都会推送值。

所以,如果你有

retryWhen(subjectErrors => subjectErrors.pipe(a(), b()))

本质上是一样的:

const subjectErrors = new Subject();
subjectErrors.pipe(a(), b()).subscriber(innerSubscriber);

一个 innerSubscriberretryWhen 内使用同样,它的主要作用是通知值( next notification)何时到达。

发生这种情况时,源将是 重新订阅 .在这种情况下,source是一个发出http请求的observable,当发生错误时,它会发送一个 error通知;如果请求成功,它将发出 next通知,后跟 complete通知。
take(5)来自 retryWhen(errors => errors.pipe(delay(1000), take(5)))表示当达到 5 次尝试时, innerSubscriber (上面的那个)将发出 complete通知。

然后你有 last ,其中有 无默认值 .这意味着当它收到 complete通知,未收到任何 next之前的通知,它会发出一个错误(默认行为)。

然后错误被 catchError() 捕获。在你的影响。所以这应该解释为什么这种方法有效。

What is weird is, that when the http-interceptor uses the operator retry rather than retryWhen it works just fine.



这是我无法解释的原因,因为使用上一节中的信息,它应该可以正常工作,创建的流应该是相同的。

如果你有

load () {
return this.http.get(...);
}

并假设拦截器是您唯一使用的拦截器,在

mergeMap(() =>
this.globalStatsService.load().pipe(
map(stats =>
globalStatsActions.loaded({
latestStats: stats
})
),
catchError(() => of(globalStatsActions.loadFailed())) // not being called using the http-interceptor
)
)
this.globalStatsService.load()应该是一样的

of(request).pipe(
concatMap(
req => new Observable(s => { /* making the request.. */ }).pipe(
retryWhen(errors => errors.pipe(delay(1000), take(5))),
last(),
)
)
)

这应该与上一节中发生的情况相同。

所以,如果我没有遗漏任何东西, catchError应该达到。

如果没有,则可能意味着您还有其他 catchErrorlast已收到一个值,因此它不会引发错误。

在这种情况下它会记录一些东西吗?

    // here the NGRX failure action is not being triggered after five failing requests
return httpHandler.handle(nextRequest).pipe(
retryWhen(errors => errors.pipe(delay(1000), take(5))),
tap(console.log),
last()
);

编辑

可以在 source code 中看到,发生请求的可观察对象将通过其订阅者发送一个事件,指示请求已被分派(dispatch)。

考虑到这一点,您可以使用 filter运算符(operator):

return httpHandler.handle(nextRequest).pipe(
filter(ev => ev.type !== 0),
retryWhen(errors => errors.pipe(delay(1000), take(5))),
last()
);

关于angular - NGRX:http 重试拦截器导致不触发失败操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60910555/

24 4 0
文章推荐: Python:计算并替换同一次正则表达式?
文章推荐: 旋转带有标题的数据框
文章推荐: typescript :此表达式不可调用。类型 '{ getUserInfo(requestData: object): Promise; }' 没有调用签名