我有一个Angular应用程序,它每2分钟更新一次jwt。有一个潜在的问题,就是在更新jwt的同时,用户可能会执行一些操作,从而触发与旧jwt一起的另一个http调用。
我如何确保renewjwt()在另一个可能的http调用触发之前完成?
我的最初想法是在调用renewjwt()之前以及完成后的回调函数中切换全局标志。
是否有使用本地Angular或rxjs完成此操作的好方法?
答案 0 :(得分:0)
您可以使用delayWhen
运算符,该运算符将基于另一个可观察到的值延迟发射的值。
为此,您可以创建如下所示的可观察对象:
function renewTokenIfNeeded$(): Observable<void> {
console.log('Renew token start');
/**
* Here you should have have :
* If current token is valid,
* ---- then return of(number),
* else
* ---- then return this.http.post([...])
*/
// for demonstration prupose i always renew the token.
return of(null).pipe(delay(
Math.floor(Math.random() * 1000) + 1
), tap(() => console.log('renew token stop')));
}
/**
* Each 100 ms i trigger new dummy http request. By exhaustMap i will ignore all future "interval" emission until my dummy http request is complete stream.
*/
const renewTokensTimer$ = interval(100).pipe(exhaustMap(() => renewTokenIfNeeded$()));
数据流看起来像:
|...|...|...|................|...|...|...|
1 /像这样,我有一个流,它将每100ms发出一个新数字,直到您认为您的电流变脏为止。
2 /然后将执行http请求以获取新请求。
3 /在您耗尽http请求之前,可观察到的间隔源将不会发出新值。
然后您可以像下面这样简单地使用它:
of(null) // Create dummy observable.
.pipe(delayWhen(() => renewTokenIfNeeded$())) // Delay it if token have to be renew.
.pipe(mergeMap(() => myRegularHttpRequest$)) // perform my http request, i am 100% here i have fresh JWT
.subscribe(console.log) // You can safely consume the API answer.
答案 1 :(得分:0)
我通过Promise
来存储待处理的Promise,以便在其已发送但尚未收到答复时进行更新。
auth服务的getToken
函数返回一个Promise
:
if (this.promiseRefreshToken) {
/* Path 1 */
this.log.debug('Refresh token is already pending, waiting for the answer to be received.');
return this.promiseRefreshToken;
} else {
/* Path 2 */
if /* no need to renew */
return Promise.resolve(token);
else
return getRefreshToken();
}
refreshToken
函数实际上负责正确设置promiseRefreshToken
(服务的成员变量):
return this.promiseRefreshToken = this.api_query./* API QUERY FOR TOKEN */
.then(api_resp => {
this.promiseRefreshToken = null;
return /* the token */;
})
.catch(api_error => {
this.promiseRefreshToken = null;
return Promise.reject('Error...');
});
当回复真正到来时,请不要忘记将Promise
还原为null,以便后续调用使用常规逻辑(上述路径2)。
这样,可以确保您永远不会有两个并发刷新令牌的请求。