3

我有一个 Angular 应用程序,它每 2 分钟更新一次 jwt。有一个潜在的问题是,当 jwt 更新时,用户可能会执行一些操作会触发另一个 http 调用 go with old jwt。

如何确保在另一个潜在的 http 调用触发之前完成 renewjwt()?

我最初的想法是在 renewjwt() 调用之前和完成后的回调函数中切换一个全局标志。

有没有使用原生 Angular 或 rxjs 完成此任务的好方法?

4

2 回答 2

0

您可以使用delayWhen运算符来延迟基于另一个可观察到的发射值。

为此,您可以创建 observable,如下所示:

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 / 像这样我有流,它将每 100 毫秒发出新的数字,直到你认为你的电流是脏的。

2/ 然后它会执行 http 请求来获取新的请求。

3/ 间隔源 observable 不会发出新值,直到您耗尽 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.

现场直播

于 2019-05-30T16:00:32.043 回答
0

我通过Promise在已发送且尚未收到回复时存储待处理的 Promise 以进行续订来做到这一点。

getTokenauth 服务的函数返回一个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)。

这样,可以保证您永远不会有两个并发的令牌刷新请求。

于 2019-06-10T17:48:53.793 回答