Angular 角度-http拦截器-http速率限制器-滑动窗口

Angular 角度-http拦截器-http速率限制器-滑动窗口,angular,rxjs,angular-http-interceptors,sliding-window,rxjs-subscriptions,Angular,Rxjs,Angular Http Interceptors,Sliding Window,Rxjs Subscriptions,我有一个用例,需要限制传出http请求的数量。是的,我在服务器端有速率限制器,但在前端也需要限制活动http请求的数量。因此,我试图实现一个滑动窗口协议,在任何时候,我只有n个活动请求 使用Rxjs的这种方法通常效果很好,请参见此处: 但我不清楚如何使用http拦截器的相同逻辑。我的以下尝试在编译时失败,错误如下: 类型“Subscription”缺少类型“Observable”中的以下属性:\u isScalar、source、operator、lift和114更多。(2740) 那么,我如

我有一个用例,需要限制传出http请求的数量。是的,我在服务器端有速率限制器,但在前端也需要限制活动http请求的数量。因此,我试图实现一个滑动窗口协议,在任何时候,我只有n个活动请求

使用Rxjs的这种方法通常效果很好,请参见此处:

但我不清楚如何使用http拦截器的相同逻辑。我的以下尝试在编译时失败,错误如下:

类型“Subscription”缺少类型“Observable”中的以下属性:\u isScalar、source、operator、lift和114更多。(2740)

那么,我如何在http拦截器上同时返回一个可观察的队列和维护一个队列呢?我的方法有缺陷吗?我可以使用http拦截器来限制http速率吗

@Injectable()
export class I1 implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const modified = req.clone({ setHeaders: { "Custom-Header-1": "1" } });

    return next
      .handle(req)
      .do((ev: HttpEvent<any>) => {
        if (ev instanceof HttpResponse) {
          console.log(ev);
        }
      })
      .pipe(
        bufferTime(1000, null, 1),
        filter(buffer => buffer.length > 0),
        concatMap(buffer => of(buffer).pipe(delay(1000)))
      )
      .subscribe(console.log);
      }
    }
@Injectable()
导出类I1实现HttpInterceptor{
拦截(

req:HttpRequest

在拦截器上,您返回的是订阅,而不是可观察的订阅

如果删除
.subscribe(console.log)
行,它应该可以正常编译。订阅由使用者完成

如果要将发出的所有信息都记录到console.log中,请使用
点击(next=>…)
操作符


编辑-哼,它解决了编译错误,但我不确定它是否能如您所愿工作……我不完全理解拦截器是如何工作的。

如果您想了解拦截器和HttpClientModule如何在引擎盖下工作的更多信息,您可以查看这篇文章:

我的方法有缺陷吗? 在这种情况下,问题在于
next.handle
预期将返回一个可观察的,但通过订阅它,它将返回一个订阅

为了更好地理解原因,我将粘贴一个从上面链接的文章复制的片段:

const obsBE$=新的可观察对象(obs=>{
定时器(1000)
.订阅(()=>{
//log(“%c[可观察],“颜色:红色;”);
obs.next({响应:{数据:['foo','bar']}});
//停止接收值!
obs.complete();
})
return()=>{
console.warn(“我已经有足够的值了!”);
}
});
//在链中组成拦截器
常量obsI1$=obsBE$
.烟斗(
轻触(()=>console.log(“%c[i1]”,'color:blue;'),
映射(r=>({…r,i1:'被i1截获!'}))
);
设retryCnt=0;
常量obsI2$=obsI1$
.烟斗(
轻触(()=>console.log(“%c[i2]”,颜色:绿色;),
映射(r=>{
如果(++retryCnt{
返回getRefreshToken()
.烟斗(
switchMap(()=>/*obsI2$*/捕获),
)
})
);
常量obsI3$=obsI2$
.烟斗(
轻触(()=>console.log(“%c[i3]”,颜色:橙色;),
映射(r=>({…r,i3:'被i3截获!'}))
);
函数getRefreshToken(){
返回计时器(1500)
.管道(q
映射(()=>({token:'token HERE'})),
);
}
函数get(){
返回obsI3$
}
得到()
.subscribe(console.log)
/* 
-->
[i1]
[i2]
我已经有足够的价值观了!
[i1]
[i2]
我已经有足够的价值观了!
[i1]
[i2]
我已经有足够的价值观了!
[i1]
[i2]
[i3]
{
“答复”:{
“数据”:[
“福”,
“酒吧”
]
},
“i1”:“被i1截获!”,
“i3”:“被i3截获!”
}
我已经有足够的价值观了!
*/

要点是拦截器创建某种类型的,该链以负责发出实际请求的可观察节点结尾。是链中的最后一个节点:


返回新的可观察对象((observer:observer)您说的是“活动请求”-浏览器已经对HTTP 1.1的每台主机进行了限制,例如,请参见。是的,我知道。考虑到http2,其中的连接数可能比http1.1的连接数高出很多。这是否回答了您的问题?以下是一些关于您答案的想法。您的更改删除了编译错误,但我仍然不知道它是否存在可以在http拦截器上使用滑动窗口。拦截器函数需要返回一个可观测值,但滑动窗口只有在和数组或嵌套的可观测值返回时才有意义。或者至少这是我对Rxjs的最好理解。谢谢你的深入回答。我知道这应该如何工作。我喜欢它的简单性,但我得到了类型当我遵循这些指导原则时出现了不匹配。@matcheek现在应该可以成功编译了:只需再问一个问题。在重新检查上面的stackblits时,我注意到两件事:1.与SO答案不同,我在截取调用中看不到“subscribe”。2.所有http查询都分配了相同的响应。或者至少在我看来是这样。Wo你介意重审你的答案还是stackblitz吗?@matcheek在答案
intercept()中
订阅只是为了演示。它们是以角度自动订阅的,因此您不必担心。关于第二点,您是对的,负责分配响应的逻辑应该位于拦截器中,而不是服务中。请告诉我它是否有效,以便我可以更新答案。