Angular HttpClient:进一步 api 调用等待第一个完成
Angular HttpClient: Make further api calls wait for the first one to finish
我有一个使用登录 cookie 的应用程序,它与大多数 api requests/calls 一起发送来验证用户。 (登录成功后由服务器设置。)
问题是,我的应用程序在启动时同时进行了一堆 api 调用,这导致调用具有无效的会话 ID,然后在服务器端为每个调用重新创建这些调用,因此它们最终以不同的会话 ID => 用户已注销。
我的计划是在彼此允许之前发送一个 api 呼叫。但不知何故我无法让它以正确的顺序工作。
我想出了一个承诺,它将在我的包装器构造函数中的第一次调用完成后得到解决,就像这样
private firstCallMade: Promise<any>;
constructor(
private http: HttpClient,
private settings: SettingsProvider)
{
this.settings.getAsyncString("apiEndpoint").then(res =>
{
this.apiUrl = res;
this.firstCallMade = new Promise((resolve, reject) =>
{
this.http.get(this.apiUrl + this.firstCallEndpoint, { withCredentials: true })
.subscribe(
(result) => {
this.logger.system(this, 'First Call', `First call successful: ${JSON.stringify(result)}`);
resolve();
},
(error) => {
this.logger.system(this, 'First Call', `First call failed: ${JSON.stringify(error)}`);
resolve();
});
});
});
}
在其他包装器方法中我是这样使用的
get<T>(endpoint: string): Observable<T>
{
return new Observable<T>(subscriber =>
{
this.firstCallMade.then(_ =>
{
this.http.get<T>(this.apiUrl + endpoint)
.subscribe(
next => subscriber.next(next),
error => subscriber.error(error));
});
});
}
但这不起作用。
我的代码有误吗?
编辑澄清
想要的是全部,但第一个调用可以同时进行,在第一个调用完成后(从而为后续调用设置正确的 cookie 数据)。
1 你不需要forkJoin,你需要mergeMap或concatMap,forkJoin通常是坏的,为什么?因为如果一个请求失败,那么其他所有请求都会失败。
mergeMap 和 concatMap 如果十个请求之一失败,其他九个继续尝试完成。
mergeMap 和 concatMap 之间的区别在于它们执行请求的方式,在 mergeMap 中,它们在 "one push" 中发送到服务器,我的意思是,假设您想提取 10 个日期,mergeMap 然后执行10 个日期的请求无需等待前一个日期完成,而 concatMap 等待前一个日期完成以将新请求添加到队列中。
这里有一个 "how to use concatMap, mergeMap and forkJoin" 的例子:https://angular-bojdob.stackblitz.io
我有一个使用登录 cookie 的应用程序,它与大多数 api requests/calls 一起发送来验证用户。 (登录成功后由服务器设置。)
问题是,我的应用程序在启动时同时进行了一堆 api 调用,这导致调用具有无效的会话 ID,然后在服务器端为每个调用重新创建这些调用,因此它们最终以不同的会话 ID => 用户已注销。
我的计划是在彼此允许之前发送一个 api 呼叫。但不知何故我无法让它以正确的顺序工作。
我想出了一个承诺,它将在我的包装器构造函数中的第一次调用完成后得到解决,就像这样
private firstCallMade: Promise<any>;
constructor(
private http: HttpClient,
private settings: SettingsProvider)
{
this.settings.getAsyncString("apiEndpoint").then(res =>
{
this.apiUrl = res;
this.firstCallMade = new Promise((resolve, reject) =>
{
this.http.get(this.apiUrl + this.firstCallEndpoint, { withCredentials: true })
.subscribe(
(result) => {
this.logger.system(this, 'First Call', `First call successful: ${JSON.stringify(result)}`);
resolve();
},
(error) => {
this.logger.system(this, 'First Call', `First call failed: ${JSON.stringify(error)}`);
resolve();
});
});
});
}
在其他包装器方法中我是这样使用的
get<T>(endpoint: string): Observable<T>
{
return new Observable<T>(subscriber =>
{
this.firstCallMade.then(_ =>
{
this.http.get<T>(this.apiUrl + endpoint)
.subscribe(
next => subscriber.next(next),
error => subscriber.error(error));
});
});
}
但这不起作用。
我的代码有误吗?
编辑澄清 想要的是全部,但第一个调用可以同时进行,在第一个调用完成后(从而为后续调用设置正确的 cookie 数据)。
1 你不需要forkJoin,你需要mergeMap或concatMap,forkJoin通常是坏的,为什么?因为如果一个请求失败,那么其他所有请求都会失败。
mergeMap 和 concatMap 如果十个请求之一失败,其他九个继续尝试完成。
mergeMap 和 concatMap 之间的区别在于它们执行请求的方式,在 mergeMap 中,它们在 "one push" 中发送到服务器,我的意思是,假设您想提取 10 个日期,mergeMap 然后执行10 个日期的请求无需等待前一个日期完成,而 concatMap 等待前一个日期完成以将新请求添加到队列中。
这里有一个 "how to use concatMap, mergeMap and forkJoin" 的例子:https://angular-bojdob.stackblitz.io