Угловая блокировка (синхронизация) http-вызова - PullRequest
3 голосов
/ 30 мая 2019

У меня есть приложение Angular, которое обновляет JWT каждые 2 минуты.Существует потенциальная проблема, пока jwt обновляется, пользователь может выполнить какое-то действие и запустить еще один http-вызов со старым jwt.

Как я могу убедиться, что renewjwt () завершен до того, как другой потенциальный http вызовет пожар?

Моя первоначальная идея - переключить глобальный флаг перед вызовом renewjwt () и в функции обратного вызова, когда онготово.

Есть ли хороший способ сделать это с помощью родного Angular или rxjs?

Ответы [ 2 ]

0 голосов
/ 10 июня 2019

Я делаю это через Promise, сохраняя ожидающее Обещание для продления, когда оно было отправлено, и ответ еще не получен.

Функция 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 в ноль для последующих вызовов, чтобы использовать обычную логику (путь 2 выше).

Таким образом, гарантируется, что у вас никогда не будет двух одновременных запросов на обновление токена.

0 голосов
/ 30 мая 2019

Вы можете использовать оператор 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 / Вот так у меня есть поток, который будет выдавать новое число каждые 100 мс, пока вы не посчитаете свой ток грязным.

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-документ

...