javascript - 重试失败的 API 调用到 Angular 中的另一个源
问题描述
如果对当前源的调用失败,我想实现一个重试对另一个源的 API 调用的逻辑。我希望它在服务层中处理,而不是在每个组件中实现这个逻辑。
例如,我在端点服务中有这样的功能
getAll(): Observable<IssueListItem[]> {
let endpointUrl = `${this.apiConnectionService.getApiUrl()}api/Issues`;
return this.http.get<IssueListItem[]>(endpointUrl, { headers: this.dataService.requestHeaders })
.pipe(retryOtherApi(this.apiConnectionService),
catchError(error => this.handleError(error)));
}
此函数的使用者如下所示:
ngOnInit() {
this.issuesEndpointService.getAll()
.subscribe(_ => this.issues = _);
}
我希望它对重试逻辑一无所知。
因此,我尝试创建一个操作员“retryOtherApi”,在其中将原点切换到另一个原点。
export function retryOtherApi(apiConnectionService: ApiConnectionService) {
const maxRetry = apiConnectionService.apiOriginsCount;
return (src: Observable<any>) => src.pipe(
retryWhen(_ => {
return interval().pipe(
flatMap(count => {
console.log('switch to: ' + apiConnectionService.getApiUrl())
apiConnectionService.switchToOther();
return count === maxRetry ? throwError("Giving up") : of(count);
})
);
})
);
}
切换工作,但不幸的是,整个 getAll 函数没有被调用,它使用相同的旧 URL 重试 n 次。
所以问题是如果当前 API 变得不可用,如何实现对其他 API 逻辑的公共重试。
如果将问题重新表述为更常见的情况,它就像如果当前一个参数失败,如何用其他参数调用 HTTP 端点。
解决方案
public getAll(): Observable<IssueListItem[]> {
let call = () => {
let endpointUrl = `${this.apiConnectionService.getApiUrl()}api/Issues`;
return this.http.get<IssueListItem[]>(endpointUrl, { headers: this.dataService.requestHeaders })
};
return <Observable<IssueListItem[]>>call()
.pipe(
retryOtherApi(this.apiConnectionService, () => call()),
catchError(error => this.handleError(error))
);
}
这是一个重试运算符:
export function retryOtherApi(apiConnectionService: ApiConnectionService, recall: () => Observable<any>) {
const maxRetry = apiConnectionService.apiOriginsCount;
let count = 0;
let retryLogic = (src: Observable<any>) => src.pipe(
catchError(e => {
if (e.status === 0) {
apiConnectionService.switchToOther();
console.log('switch to: ' + apiConnectionService.getApiUrl())
return count++ === maxRetry ? throwError(e) : retryLogic(recall());
} else {
return throwError(e);
}
}));
return retryLogic;
}
它有效,但是:
- 现在我需要为其他线程实现逻辑,不要同时切换 api。
- TS 类型转换有一些问题,这就是我在返回之前对类型进行硬编码的原因。
推荐阅读
- amadeus - Flight Low-fare Search API - 返回 500 错误
- traefik - Traefik ForwardAuth 可以对具有不同 URL 路径的多个 API 进行身份验证吗?
- javascript - 我的 npm 打包的 vue 组件导出有什么问题?
- postgresql - PostgreSQL上的内存全行锁定问题
- excel - 删除包含特定字符串的行,同时保留单元格为空白的行
- ionic3 - 如何在离子中使用多部分
- java - Java将子类型实例添加到超类型集合中?
- node.js - How to display html link inside table cell using reactjs material-table
- django - 在 django 模板中解码一个值
- python - 如何在python中将SQL查询结果发送到电子邮件