我正在与API服务器交谈,该服务器使用一次性身份验证令牌,每个请求都会重新发出(即生成一个新的令牌)。如果使用同一令牌同时发出两个API请求,则其中一个请求会因为令牌过期而失败,错误处理程序可能会被不必要地触发。
我想要做的是构建一个等待机制,以便一次只发出一个HTTP请求,随后的请求将被排队,直到前一个请求完成。
我想以一种通用的方式构建它,这样我就可以有一个服务层来发出请求,所以它对上层是透明的,但是我正在努力找到一种简洁的方法来做到这一点。有什么建议吗?
-- edit --
我应该提到的是,所有后续的接口调用URL/请求主体都直接依赖于前一个接口调用的响应,例如GET /books?apiKey=ABC返回:
{ 'apiKey': 'XYZ', 'names': [...] }
排队的下一个请求必须等待此响应并附加新的apiKey:GET /authors?apiKey=XYZ
在上面的示例中,执行GET /authors?apiKey=ABC将导致错误。
如果两个超文本传输协议请求之间有很强的依赖性(例如,请求图书,然后根据其id请求特定图书的作者),它们可以使用flatMap、嵌套订阅等进行序列化。
-- edit two --
我有两个类似下面的组件,假设这两个组件都在启动时调用API调用。
class ComponentA {
ngOnInit(api:<BookApi extends CommonApi>) {
this.api.list().subscribe(x => {...});
}
}
class ComponentB {
ngOnInit(api:<CityLookupApi extends CommonApi>) {
this.api.list().subscribe(x => {...});
}
}所有的应用程序接口服务都扩展了一个通用的应用程序接口来隐藏它背后的apiKey处理,这样组件就可以使用更高级别的调用来帮助理解。问题是,如果两个组件几乎同时初始化,两个调用都可以使用相同的api密钥,其中一个调用将失败。但是,我不能预先使用forkJoin创建这些可观察到的批处理,因为它们是在运行时异步创建和订阅的,因为它们是在各自的组件中创建的。
发布于 2018-03-29 23:06:52
您可以使用Observable.concat(...myArrayOfAjaxRequestObservable)逐个使用每个可观察对象。
只有Observable.contact必须为自己订阅您的ajax请求。这是唯一100%确定请求不会被你的代码的另一部分触发的方法。
更多信息请点击此处:https://www.learnrxjs.io/operators/combination/concat.html
-更新
示例:https://stackblitz.com/edit/angular-66ic6c?file=app%2Fapp.component.ts
发布于 2018-03-29 23:08:59
Yanis-git回答了排队问题。如果您想在其他请求发生时阻止所有请求,请使用exhaustMap。
发布于 2018-03-29 23:25:07
我会考虑将mergeMap和它的concurrency参数一起使用。
这是一段模拟我想要的东西的代码片段
import {Observable} from 'rxjs';
import {Subject} from 'rxjs';
const requestsRemoteService = new Subject<string>();
const requestStream = requestsRemoteService.asObservable();
// this function simulates the execution of the request
const requestExecution = (input: string) => {
return Observable.of(input + ' executed').delay(2000);
}
// this is what the service should to queue the requests
requestStream
// the last parameter, set to 1, is the level of concurrency
.mergeMap(requestInput => requestExecution(requestInput), 1)
.subscribe(
data => console.log(data),
err => console.error(err),
() => console.log('DONE')
)
// these are the various requests coming to the service
setTimeout(() => requestsRemoteService.next('First request'), 1);
setTimeout(() => requestsRemoteService.next('Second request'), 2);
setTimeout(() => requestsRemoteService.next('Third request'), 3);https://stackoverflow.com/questions/49559371
复制相似问题