【发布时间】:2019-10-16 18:53:25
【问题描述】:
我有一个函数为我处理多个 API 请求,如果失败,则将每个请求置于重试模式。现在,如果一个请求已经在重试循环中并且同一 API 调用的另一个实例到达,我的函数无法跟踪这一点并再次在重试循环中添加冗余 API 调用。
Assuming i am placing a call to
/api/info/authors
What is happening
1stREQ| [re0]------>[re1]------>[re2]------>[re3]------>[re4]------>[re5]
2ndREQ| [re0]------>[re1]------>[re2]------>[re3]------>[re4]------>[re5]
What should happen,
1stREQ| [re0]------>[re1]------>[re2]------>[re3]------>[re4]------>[re5]
2ndREQ| [re0]/ (MERGE)
以下是我的服务和我的重试功能,
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { retryWhen, mergeMap, finalize, share, shareReplay } from 'rxjs/operators';
import { Observable, throwError, of, timer } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DataService {
constructor(private http: HttpClient) { }
private apiUrl: string = 'http://localhost/api-slim-php/public/api';
public dataServerURL: string = 'http://localhost/';
/*
This function fetches all the info from API /info/{category}/{id}
category : author & id : '' or 1,2,3... or a,b,c...
category : form & id : '' or 1,2,3...
category : location & id : '' or 1,2,3...
category : school & id : '' or 1,2,3...
category : timeframe & id : '' or 1,2,3...
category : type & id : '' or 1,2,3...
*/
public getInfoAPI(category: string, id: string = "", page: string = "1", limit: string = "10") {
var callURL: string = '';
if (!!id.trim() && !isNaN(+id)) callURL = this.apiUrl + '/info/' + category + '/' + id;
else callURL = this.apiUrl + '/info/' + category;
return this.http.get(callURL, {
params: new HttpParams()
.set('page', page)
.set('limit', limit)
}).pipe(
retryWhen(genericRetryStrategy({ maxRetryAttempts: 5, scalingDuration: 1000 })),
shareReplay()
);
}
}
export const genericRetryStrategy = ({
maxRetryAttempts = 3,
scalingDuration = 1000,
excludedStatusCodes = []
}: {
maxRetryAttempts?: number,
scalingDuration?: number,
excludedStatusCodes?: number[]
} = {}) => (attempts: Observable<any>) => {
return attempts.pipe(
mergeMap((error, i) => {
const retryAttempt = i + 1;
// if maximum number of retries have been met
// or response is a status code we don't wish to retry, throw error
if (
retryAttempt > maxRetryAttempts ||
excludedStatusCodes.find(e => e === error.status)
) {
console.log(error);
return throwError(error);
}
console.log(
`Attempt ${retryAttempt}: retrying in ${retryAttempt *
scalingDuration}ms`
);
// retry after 1s, 2s, etc...
return timer(retryAttempt * scalingDuration);
}),
finalize(() => console.log('We are done!'))
);
};
注意:
有人建议shareReplay(),所以我尝试实现它,但它无法处理来自其他两个组件/来源的相同请求。
以下应该只有 6,而不是快速点击调用相同 API 的两个按钮时为 12(缩放持续时间为 1000 毫秒)。
注意:
请避免使用FLAGS,我认为这是最后的核弹。
【问题讨论】:
-
见this answer 我想你可能需要使用
catchError运算符,并且不需要shareReplay。 -
我已经声明了我的自定义ErrorHandler,看到
It happens,我应该怎么做才能纠正这个错误?使用标志? -
我不明白你的意思,但我认为你应该在
retryWhen之后添加catchError运算符,并删除shareReplay或在管道中将其移动到getInfoAPI之后 -
@TheNsn666 想知道一个有趣的事情吗?我有我的主题颜色
#666,看看谁在这里帮助我建立我的网站!TheNsn666. -
快一个棘手的,你的用例更像是缓存和无效缓存的情况
标签: angular rxjs observable httprequest