Angular/Rxjs-在前一个请求完成之前排队/阻止HTTP请求

Angular/Rxjs-在前一个请求完成之前排队/阻止HTTP请求,angular,rxjs,Angular,Rxjs,我所说的是一个API服务器,它使用一次性身份验证令牌,每个请求都会重新发布(即生成一个新令牌)。如果使用同一令牌同时发出两个API请求,则其中一个由于令牌过期而失败,并且可能会不必要地触发错误处理程序 我想做的是构建一个等待机制,这样一次只发出一个HTTP请求,后续请求将排队,直到前一个请求完成 我想以一种通用的方式构建它,这样我就可以有一个服务层来发出请求,这样它对上层是透明的,但是我正在努力找到一种简洁的方法来实现这一点。有什么建议吗 --编辑-- 我应该提到的是,所有后续API调用URL/

我所说的是一个API服务器,它使用一次性身份验证令牌,每个请求都会重新发布(即生成一个新令牌)。如果使用同一令牌同时发出两个API请求,则其中一个由于令牌过期而失败,并且可能会不必要地触发错误处理程序

我想做的是构建一个等待机制,这样一次只发出一个HTTP请求,后续请求将排队,直到前一个请求完成

我想以一种通用的方式构建它,这样我就可以有一个服务层来发出请求,这样它对上层是透明的,但是我正在努力找到一种简洁的方法来实现这一点。有什么建议吗

--编辑--

我应该提到的是,所有后续API调用URL/请求主体直接依赖于前一个API调用的响应,例如,
GET/books?apiKey=ABC
返回:

{
“apiKey”:“XYZ”,
“名称”:[…]
}

排队的下一个请求必须等待此响应并附加新的apiKey:
GET/authors?apiKey=XYZ

在上面的示例中,执行
GET/authors?apiKey=ABC
将 导致错误

如果两个HTTP请求(例如请求书,然后根据其id请求该特定书的作者)之间存在强烈的依赖性,则可以使用平面图、嵌套订阅等对它们进行序列化。我需要与此类似的功能,但可以以通用方式将请求添加到运行时序列化的队列中

--编辑两个--

我有如下两个组件,假设它们都在启动时调用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 => {...});
    }
}
类组件a{
ngOnInit(api:){
this.api.list().subscribe(x=>{…});
}
}
类组件B{
ngOnInit(api:){
this.api.list().subscribe(x=>{…});
}
}

所有API服务都扩展了一个公共API,以隐藏其背后的apiKey处理,以便组件可以使用更高级别的调用来帮助理解。问题在于,如果两个组件几乎同时初始化,则两个调用可能使用相同的api键,其中一个将失败。但是,我无法使用forkJoin等工具预先创建这些可观察的批处理,因为它们是在运行时异步创建和订阅的,因为它们是在各自的组件中创建的

您可以使用
Observable.concat(…myArrayOfAjaxRequestObservable)
让每个Observable逐个消费

只有Observable.contact必须订阅您的ajax请求。这是确保请求不会被代码的另一部分触发的唯一方法

更多信息请点击此处:

---更新---


示例:

您可以使用
Observable.concat(…myArrayOfAjaxRequestObservable)
逐个使用每个Observable

只有Observable.contact必须订阅您的ajax请求。这是确保请求不会被代码的另一部分触发的唯一方法

更多信息请点击此处:

---更新---


示例:

Yanis git回答了排队问题。如果要在其他请求发生时阻止所有请求,请使用
defaustmap


Yanis git回答了排队问题。如果要在其他请求发生时阻止所有请求,请使用
defaustmap


< P>我会考虑使用<代码> CyMeMaP <代码>及其<代码>并发< /代码>参数

这是一段模拟我的意图的代码

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);
从'rxjs'导入{Observable};
从'rxjs'导入{Subject};
const requestsRemoteService=新主题();
const requestStream=requestsRemoteService.asObservable();
//此函数模拟请求的执行
const requestExecution=(输入:字符串)=>{
返回可观测的(输入+执行)延迟(2000);
}
//这就是服务应该为请求排队的地方
请求流
//最后一个参数设置为1,是并发级别
.mergeMap(requestInput=>requestExecution(requestInput),1)
.订阅(
data=>console.log(数据),
err=>console.error(err),
()=>console.log('DONE'))
)
//这些是服务的各种请求
setTimeout(()=>requestsRemoteService.next('First request'),1);
setTimeout(()=>requestsRemoteService.next('Second request'),2);
setTimeout(()=>requestsRemoteService.next('Third request'),3);

<代码> > p>我将考虑使用<代码>合并代码> /COD>及其<代码>并发< /代码>参数

这是一段模拟我的意图的代码

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);
从'rxjs'导入{Observable};
从'rxjs'导入{Subject};
const requestsRemoteService=新主题();
const requestStream=requestsRemoteService.asObservable();
//此函数模拟请求的执行
const requestExecution=(输入:字符串)=>{
返回可观测的(输入+执行)延迟(2000);
}
//这就是服务应该为请求排队的地方
请求流
//最后一个参数设置为1,是并发级别
.mergeMap(requestInput=>requestExecution(requestInput),1)
.订阅(
data=>console.log(数据),
err=>console.error(err),
()=>console.log('DONE'))
)
//这些是服务的各种请求
setTimeout(()=>requestsRemoteService.next('First request'),1);
setTimeout(()=>requestsRemoteService.next('Second request'),2);
setTimeout(()=>requestsRemoteService.next('Third request'),3);

这可能是操作的方法。我添加了排气图答案,作为一些边缘情况的替代解决方案。向上投票:)嗨@TomaszKula我不知道为什么我们需要使用Observable.concat的
exhaustMap
。正如你们在我的附件中看到的,所有的请求都在一步一步地消耗,直到当前的answ,所有的请求都被阻塞