我正在使用HttpInterceptor
向每个API请求添加授权令牌。
然后,我使用next.handle(newRequest).subscribe(...)
订阅此请求,并检查返回的结果/错误。
请求成功后,它将被继续传递。 但是当不是因为授权令牌无效时,拦截器将刷新授权令牌并重试请求。 如果重试失败,则整个过程将按我的预期失败。
然后的问题是,可以并且将几乎同时发送多个请求,这导致了这种情况,即较早的请求发现了auth令牌已过期并启动了令牌刷新过程。然后-在服务器返回刷新的令牌之前-第二个调用使用过期的auth令牌发出请求,从而导致另一个刷新,使第一次刷新的“新”获取的auth令牌无效,依此类推。这两个调用都将成功重试,但这可以连续快速进行多达100次刷新。
问题
如何在第一个请求刷新身份验证令牌时推迟第一个请求之后的所有请求,以便每个后续请求都使用第一个请求的新获取的身份验证令牌?
是否可以使用持有诺言的成员变量,该诺言将在每次刷新时创建,并由第一个拦截调用创建,而其他调用需要等待?还是第二个近乎同时的呼叫可以通过承诺创建而滑落?伪代码:
class Interceptor implements HttpInterceptor
{
private refreshPromise: Promise<void>;
private authToken;
intercept(req, next)
{
// ... subscribe for request with auth token added...
observable.subscribe(
result => // ... do something
error => {
//... if error because of token expiration
if(this.refreshPromise)
await this.refreshPromise;
this.refreshPromise = new Promise((resolve, reject) =>
{
refreshToken().subscribe(
result => {
this.authToken = result.token;
resolve();
this.refreshPromise = null;
},
error => // all is lost
);
});
}
);
// ... request fails
}
}
我认为这是不可行的,因为当我null the promise
时,那些已排队但尚未执行的操作将失败,或者在清空之前会通知每个等待诺言的人吗?!?
替代方法
我的第二个想法是拥有一个成员变量标志,该标志指示刷新是否正在运行,如果是,则传递给intercept
的那些调用的请求将被添加到延迟请求的列表中并在刷新后由第一个拦截器执行。
此方法的问题是,在第一次拦截时,对HttpRequests
的其他调用intercept
的处理。因为从HttpClient到HttpBackend的链将断开,并且我无法将延迟请求的结果作为第一个请求的结果返回。
有什么建议或解决方案吗?
亲切问候