角度阻塞(同步)http调用

时间:2019-05-30 15:10:25

标签: angular http rxjs synchronous

我有一个Angular应用程序,它每2分钟更新一次jwt。有一个潜在的问题,就是在更新jwt的同时,用户可能会执行一些操作,从而触发与旧jwt一起的另一个http调用。

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

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

是否有使用本地Angular或rxjs完成此操作的好方法?

2 个答案:

答案 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.

live poc

答案 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)。

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