AngularInDepth уходит от Medium. Эта статья, ее обновления и более свежие статьи размещены на новой платформе inDepth.dev

Некоторые новые функции были добавлены в Angular Router с версией 7.1.0:

  • Охрана маршрутизатора теперь может возвращать UrlTree. Это позволяет охраннику отменить текущую навигацию и перенаправить на URL-адрес, представленный UrlTree.
  • Теперь существует понятие «приоритета охраны», которое используется в качестве решающего фактора, когда несколько охранников возвращают UrlTree во время одной навигации.
  • Добавлен новый параметр конфигурации для runGuardsAndResolvers под названием pathParamsChange.

В этой статье мы узнаем, как начать использовать эти новые функции. Мы также поймем их мотивы и посмотрим, как они реализованы в исходных кодах Angular.

Джейсон Аден затронул многие из этих тем в своем прекрасном выступлении на AngularConnect 2018, так что обязательно ознакомьтесь с ним. Маршрутизаторская часть его выступления начинается здесь.

Выполните навигацию / перенаправления от охранников, вернув UrlTree

#26478, #26521

Мотивация

До этого изменения, когда во время навигации выполнялось несколько охранников, каждый из них мог запускать навигацию, вызывая navigateByUrl. В таких сценариях было неясно, какая навигация охранника должна выиграть.

С этим изменением средство защиты с наивысшим приоритетом, которое возвращает UrlTree, отменит текущую навигацию, и будет выполнено перенаправление на URL-адрес, представленный возвращенным UrlTree.
Мы скоро увидим, что означает «высший приоритет».

Фон

Прежде чем углубляться в это изменение, стоит понять разницу между URL и UrlTree.

Внутри Angular Router строка URL-адреса представлена ​​с использованием структуры, называемой UrlTree. Строковый URL-адрес легко преобразовать в UrlTree с помощью parseUrl метода службы Router:

const url = 'target';
const tree: UrlTree = this.router.parseUrl(url);

Если вы хотите узнать больше о взаимосвязи между URL-адресами и UrlTrees в Angular, я подробно рассказал о них в этой статье.

Перемена

До этого изменения охрана маршрутизатора могла возвращать только boolean значений. Возвращаемое значение true означает, что навигация может продолжаться, а возвращаемое значение false отменяет навигацию.

Теперь для CanActivate, CanActivateChild и CanDeactivate есть третий вариант; эти охранники могут вернуть UrlTree напрямую. В этих сценариях текущая навигация отменяется и создается новая навигация, которая направляется по пути, указанному возвращенным UrlTree. Например, если пользователь не проходит проверку подлинности, вы можете перенаправить этого пользователя прямо на страницу входа.

Пример

https://stackblitz.com/edit/router-redirects-from-guards

В этом примере приложения есть два маршрута:

Мы сделаем так, чтобы /redir всегда перенаправлял на /target вместо отображения NeverGetHereComponent. Вместо того, чтобы использовать redirectTo: 'target' внутри определения маршрута для path: 'redir', мы позволим CanActivateRouteGuard инициировать перенаправление.

Мы начнем с обычной сторожевой функции и изменим ее canActivate метод, чтобы он возвращал UrlTree вместо логического значения:

Как упоминалось ранее, parseUrl - это функция службы маршрутизатора. Он принимает URL-адрес, закодированный в виде строки, и преобразует его в UrlTree.

Наша охрана готова, поэтому мы прикрепим ее к { path: 'redir' ... } маршруту.

{ path: 'redir',
  component: NeverGetHereComponent,
  canActivate:[CanActivateRouteGuard] }

Теперь, когда мы направляемся к /redir, навигация будет продолжаться в обычном режиме, пока не будет проверена охрана. Когда наша функция защиты возвращает UrlTree, указывающий на target, переход к redir будет отменен, и начнется новая навигация с таргетингом на target. Мы можем подтвердить это, щелкнув ссылку перенаправления в Stackblitz:

а затем проверьте консоль браузера:

Это все, что нужно для настройки переадресации от маршрутных охранников!

Guard Priority

У нас часто есть несколько охранников, охраняющих маршрут. Вам может быть интересно, что происходит, когда несколько охранников пытаются выполнить перенаправление во время навигации. Что, если несколько из этих охранников вернут UrlTrees?

В Angular 7.1.0 есть понятие приоритета защиты. Приоритет защиты реализуется внутри с помощью специального оператора RxJS, называемого prioritizedGuardValue. Мы не будем здесь вдаваться в подробности реализации, но этот оператор будет следить за тем, чтобы охранник с наивысшим приоритетом выигрывал всякий раз, когда несколько охранников возвращают UrlTrees.

Рассмотрим следующий пример:

Вот как рассчитывается приоритет охраны для нескольких canActivate охранников:

  • canActivate охранников текущего маршрута обрабатываются перед любыми canActivate охранниками его дочерних элементов.
  • Внутри массива canActivate защита с индексом 0 имеет наивысший приоритет, за ней следует защита с индексом 1 и так далее.

Другой способ мышления о canActivate состоит в том, что защита, ближайшая к корню приложения, имеет наивысший приоритет. Итак, в приведенном выше фрагменте наивысший приоритет имеет CanActivateRouteGuard, за ним следует CanActivateRouteGuard2, а затем ChildCanActivateRouteGuard.

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

  • Даже если CanActivateRouteGuard2 немедленно возвращает UrlTree:
    маршрутизатор все равно будет ждать разрешения CanActivateRouteGuard, прежде чем инициировать новую навигацию.
  • Если CanActivateRouteGuard вернет UrlTree:
    , это выиграет.
  • Если он возвращает false:
    , вся навигация не выполняется (и перенаправления не происходит).
  • Если он просто возвращает true:
    , тогда будет выполнено переход к UrlTree, возвращаемому CanActivateRouteGuard2.

Вы можете увидеть, как развиваются различные сценарии, посмотрев на тесты для оператора PrioritizedGuardValue.

Вы также можете поэкспериментировать с этим stackblitz. Я рекомендую перейти к трем охранникам и изменить их задержки и возвращаемые значения, а также их порядок в массиве canActivate в app.module.ts.

runGuardsAndResolvers имеет новую опцию: pathParamsChange

#26861

Официальная документация описывает параметр runGuardsAndResolvers как:

определяет, когда будут запускаться охранники и резолверы. По умолчанию они запускаются только при изменении матричных параметров маршрута. Если установлено значение paramsOrQueryParamsChange, они также будут запускаться при изменении параметров запроса. И если установлено значение always, они будут запускаться каждый раз.

С новой опцией pathParamsChange функции защиты и преобразователя будут запускаться только при изменении пути или параметров пути. Изменения любых других типов параметров, таких как параметры матрицы или параметры запроса, не приведут к запуску средств защиты и преобразователей.

Мотивация

Как описано в Источниках:

`pathParamsChange` Запустить путь охранников и преобразователей или любое изменение параметров пути. Этот режим * полезен, если вы хотите игнорировать изменения всех необязательных параметров, таких как параметры запроса * и * матрицы *.

Пример использования

runGuardsAndResolvers - это свойство Routes, поэтому оно используется в конфигурации маршрута:

{ path: '...', runGuardsAndResolvers: 'pathParamsChange'}

Резюме

С выпуском Angular 7.1.0 функции Route Guard теперь имеют возможность возвращать UrlTree для отмены текущей навигации и перенаправления на маршрут.

Чтобы инициировать перенаправление из функции защиты, сделайте следующее:

  • Создайте функцию защиты, которая использует parseUrl для возврата UrlTree.
  • Зарегистрируйте охранника с маршрутом, как обычно

Также есть новая опция для указания того, когда запускать резолверы и функции защиты, называемые pathParamsChange, которая полезна, когда вы хотите запускать охранники и резолверы только для основных переходов и игнорировать любые дополнительные параметры, такие как матрица или параметры запроса.

Особая благодарность Джейсону Адену, Максу «Волшебнику» Корецкому и Тиму Дешрайверу за их помощь в написании этой статьи.