Угловой: ожидание параметра строки запроса, но сделайте что-нибудь еще, если он не появится

#rxjs #angular-routing

Вопрос:

Я попытался сформулировать название вопроса наиболее общим способом, который применим к моей проблеме.

У меня есть приложение Angular, в котором мне нужно выполнить аутентификацию по внешнему требованию: либо использовать параметр строки запроса token , который необходимо обменять с сервером на JWT, либо попытаться найти токен обновления JWT в локальном хранилище.

Это:

  • Сначала проверьте строку запроса: если есть параметр строки token запроса , возьмите токен, удалите любой JWT в локальном хранилище, обменяйте токен через API на два JWT ( id_token и refresh_token )
  • В противном случае перейдите к маркеру обновления: если refresh_token в локальном хранилище есть доступный, обменяйте его на JWT id_token через API
  • В противном случае, если ни один из них не доступен, пользователь не прошел проверку подлинности, и должно появиться приглашение

Я использовал наблюдаемые почти правильно

 this.queryParamMap$.unsubscribe(); this.queryParamMap$ = this.activatedRoute.queryParamMap  .subscribe(  params =gt; {  let token = params.get('token');  ........  if (!!token) {  doLoginWithToken();  else if (isJwtRefreshAvailable())  doLoginWithRefreshToken();  

В этом подходе есть одна проблема: при первом запуске приложения карта параметров запроса пуста, даже если я перейду по прямой ссылке браузера http://localhost:4200?token=AAAAAAAA . Я должен wait сделать это для следующего элемента, который содержит токен.

Это имеет два нежелательных эффекта:

  1. При первой попытке, будучи токеном undefined , приложение немедленно пытается войти в систему с помощью токена обновления
  2. Если я отфильтрую queryParamMap наблюдаемое для наличия токена, если токен никогда не присутствует, наблюдаемое никогда не будет излучать, таким образом, не активируя подписку.

Мою проблему можно обобщить/обобщить следующим образом.

У меня есть наблюдаемый, который, как я точно знаю, испускает undefined с самого первого раза, но либо в кратчайшие сроки он может быть готов с надлежащим значением, либо он не будет испускать новые значения после первоначального undefined .

Кроме того, в то время как наблюдаемый излучает undefined , и мой код начинает реагировать на него (например, путем тестирования на токен), новое значение может быть готово к излучению сразу.

Как я могу решить эту проблему в Rxjs? Обратите внимание, что доступ к токену JWT из локального хранилища является синхронной операцией, но его легко создать Observable.of(localStorage.get(KEY)) , который немедленно запускается при наличии токена обновления.

Для этого я не могу реально использовать race оператор, потому что токен обновления всегда готов и всегда выигрывает гонку.

Как я могу написать асинхронный код, который выполняет действия, подобные тем, которые я описал ранее?

В качестве конечного результата аутентификации an Observablelt;UserProfileDto | undefinedgt; выдает информацию о пользователе, которая используется для отображения персонализированной информации.

Комментарии:

1. похоже , вы могли бы использовать just debounceTime() , и если после этого списания токен останется undefined , вы будете знать, что токен не установлен и не будет присутствовать. Если вы знаете, что все выполняемые вами операции синхронны, вы можете пойти даже на debounceTime(0) то, что обработчик подписки будет выполнен в другом фрейме JavaScript без каких-либо задержек.

2. Хорошо в качестве ответа. Я попробую и то, и другое

Ответ №1:

У вас здесь 2 проблемы:

  1. При запуске вы получили значение «неопределенное» (это потому, что, вероятно, под капотом есть какой-то объект поведения, который выдает значение по умолчанию). Чтобы преодолеть это, вы можете добавить оператор RxJS (пропустить(1)), чтобы пропустить это первое значение, но:
  2. Проблема здесь в том, что если у вас вообще нет значений запроса, вы не достигнете своей функции подписки. Это потому, что queryParamMap выдаст значение только в том случае, если есть изменение (а в этом случае его нет):

Вы можете сделать это без углового, чтобы просто проанализировать URL-адрес с:

 const urlParams = new URLSearchParams(window.location.search); const params = Object.fromEntries(urlParams.entries());  

Или с помощью маршрутизатора в угловой:

 this.router.events  // Wait for the navigation end event (since component is initialized before angular router navigation is done)  .pipe(filter(event =gt; event instanceof NavigationEnd))  .subscribe((event: NavigationStart) =gt; {  // Take query params snaphot  const map = this.route.snapshot.queryParams;   });