Маршрутизация и создание URL-адресов

Когда приложение Yii начинает обрабатывать запрошенный URL-адрес, первый шаг, который требуется, - это анализ URL-адреса в маршруте. Маршрут затем используется для создания экземпляра соответствующего действия контроллера для обработки запроса. Весь этот процесс называется маршрутизацией.

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

Центральным элементом, отвечающим за маршрутизацию и создание URL, является менеджер URL-адресов, который зарегистрирован как компонент приложения urlManager. Менеджер URL-адресов предоставляет метод parseRequest() для анализа входящего запроса в маршруте и связанных параметров запроса и метода createUrl() для создания URL-адреса из заданного маршрута и связанных с ним параметров запроса.

Путем настройки компонента urlManager в конфигурации приложения вы можете позволить вашему приложению распознавать произвольные форматы URL-адресов без изменения вашего существующего кода приложения. Например, вы можете использовать следующий код для создания URL-адреса для действия post/view:

use yii\helpers\Url;

// Url::to() calls UrlManager::createUrl() to create a URL
$url = Url::to(['post/view', 'id' => 100]);

В зависимости от конфигурации urlManager, созданный URL-адрес может выглядеть как один из следующих (или другого формата). И если созданный URL запрашивается позже, он все равно будет проанализирован обратно в исходный маршрут и значение параметра запроса.

/index.php?r=post%2Fview&id=100
/index.php/post/100
/posts/100

Форматы URL-адресов

Менеджер URL-адресов поддерживает два формата URL:

  • Формат URL по умолчанию;
  • Красивый формат URL.

Формат URL по умолчанию использует параметр запроса с именем r для представления маршрута и обычных параметров запроса для представления параметров запроса, связанных с маршрутом. Например, URL /index.php?r=post/view&id=100 представляет post/view маршрута и параметр запроса id 100. Формат URL по умолчанию не требует какой-либо настройки менеджера URL-адресов и работает в любой настройке веб-сервера.

В довольно URL-формате для указания маршрута и связанных параметров запроса используется дополнительный путь, следующий за именем сценария входа. Например, дополнительный путь в URL /index.php/post/100 является /post/100, который может представлять post/view маршрута и параметр запроса id 100 с правильным правилом URL. Чтобы использовать красивый формат URL-адреса, вам необходимо разработать набор правил URL-адресов в соответствии с фактическим требованием о том, как должны выглядеть URL-адреса.

Вы можете переключаться между двумя форматами URL-адресов, переключив свойство enablePrettyUrl в менеджере URL-адресов, не меняя какой-либо другой код приложения.

Маршрутизация

Маршрутизация состоит из двух этапов:

  • Входящий запрос анализируется в маршруте и связанных параметрах запроса;
  • Для обработки запроса создается действие контроллера, соответствующее проанализированному маршруту.

При использовании формата URL по умолчанию разбор запроса в маршруте также прост, как получение значения параметра запроса GET с именем r.

При использовании красивого формата URL-адрес менеджер URL-адреса исследует зарегистрированные правила URL-адресов, чтобы найти подходящий, который может разрешить запрос в маршрут. Если такое правило не может быть найдено, будет создано исключение yii\web\NotFoundHttpException.

Как только запрос разобран в маршрут, пришло время создать действие контроллера, идентифицированное маршрутом. Маршрут разбит на несколько частей по слэшам в нем. Например, site/index будет разбит на site и index. Каждая часть является идентификатором, который может относиться к модулю, контроллеру или действию. Начиная с первой части маршрута, приложение выполняет следующие шаги для создания модулей (если есть), контроллера и действия:

  1. Установите приложение в качестве текущего модуля.
  2. Проверьте, содержит ли карта контроллера текущего модуля текущий идентификатор. Если это так, то объект контроллера будет создан в соответствии с конфигурацией контроллера, найденной на карте, и будет использоваться шаг 5 для обработки остальной части маршрута.
  3. Проверьте, относится ли идентификатор к модулю, указанному в свойстве modules текущего модуля. Если это так, модуль создается в соответствии с конфигурацией из списка модулей, и будет выполнен шаг 2 для обработки следующей части маршрута в контексте вновь созданного модуля.
  4. Относитесь к ID как идентификатору контроллера и создайте объект контроллера. Сделайте следующий шаг с остальной частью маршрута.
  5. Контроллер ищет текущий идентификатор в своей карте действий. Если он найден, он создает действие в соответствии с конфигурацией, найденной на карте. В противном случае контроллер попытается создать встроенное действие, которое определяется методом действия, соответствующим текущему идентификатору действия.

Среди вышеперечисленных шагов, если возникнет какая-либо ошибка, будет выдан yii\web\NotFoundHttpException, указывающий на отказ процесса маршрутизации.

Маршрут по умолчанию

Когда запрос разобран в пустой маршрут, вместо него будет использоваться так называемый маршрут по умолчанию. По умолчанию маршрут по умолчанию - это site/index, который ссылается на действие index контроллера site. Вы можете настроить его, настроив свойство defaultRoute приложения в конфигурации приложения следующим образом:

[
    // ...
    'defaultRoute' => 'main/index',
];

Как и в случае маршрута по умолчанию приложения, существует также маршрут по умолчанию для модулей, например, если есть модуль user, и запрос анализируется в user маршруте, то по умолчанию для модуля используется defaultRoute. По умолчанию имя контроллера default. Если в defaultRoute не указано никаких действий, свойство defaultAction контроллера используется для определения действия. В этом примере полным маршрутом будет user/default/index.

catchAll роутер

Иногда вам может потребоваться временно перевести веб-приложение в режим обслуживания и отобразить одну и ту же информационную страницу для всех запросов. Есть много способов достичь этой цели. Но один из простейших способов - это настроить свойство yii\web\Application::$catchAll, например, следующее в конфигурации приложения:

[
    // ...
    'catchAll' => ['site/offline'],
];

В указанной конфигурации действие site/offline будет использоваться для обработки всех входящих запросов.

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

Создание URL-адресов

Yii предоставляет вспомогательный метод yii\helpers\Url::to() для создания различных типов URL-адресов из заданных маршрутов и связанных с ними параметров запроса. Например:

use yii\helpers\Url;

// создает URL-адрес маршрута: /index.php?r=post%2Findex
echo Url::to(['post/index']);

// создает URL-адрес маршрута с параметрами: /index.php?r=post%2Fview&id=100
echo Url::to(['post/view', 'id' => 100]);

// создает привязанный URL-адрес: /index.php?r=post%2Fview&id=100#content
echo Url::to(['post/view', 'id' => 100, '#' => 'content']);

// создает абсолютный URL-адрес: http://www.example.com/index.php?r=post%2Findex
echo Url::to(['post/index'], true);

// создает абсолютный URL-адрес, используя схему https: https://www.example.com/index.php?r=post%2Findex
echo Url::to(['post/index'], 'https');

Обратите внимание, что в приведенном выше примере мы предполагаем, что используется формат URL по умолчанию. Если включен режим довольно URL, созданные URL-адреса будут отличаться в соответствии с используемыми правилами URL.

Маршрут, переданный методу yii\helpers\Url::to(), является контекстно-зависимым. Это может быть либо относительный маршрут, либо абсолютный маршрут, который будет нормализован в соответствии со следующими правилами:

  • Если маршрут - пустая строка, будет использоваться текущий запрошенный маршрут;
  • Если маршрут не содержит косых черт, он считается ID действия текущего контроллера и будет добавлен с уникальным значением ID текущего контроллера;
  • Если маршрут не имеет косой черты, он считается маршрутом относительно текущего модуля и будет добавлен с уникальным значением текущего модуля.

Вы можете указать маршрут с точки зрения псевдонима. Если это так, псевдоним сначала будет преобразован в фактический маршрут, который затем будет преобразован в абсолютный маршрут в соответствии с вышеприведенными правилами.

Например, предположим, что текущий модуль - admin, а текущий контроллер - post:

use yii\helpers\Url;

// запрошенный маршрут: /index.php?r=admin%2Fpost%2Findex
echo Url::to(['']);

// относительный маршрут с идентификатором действия: /index.php?r=admin%2Fpost%2Findex
echo Url::to(['index']);

// относительный маршрут: /index.php?r=admin%2Fpost%2Findex
echo Url::to(['post/index']);

// абсолютный маршрут: /index.php?r=post%2Findex
echo Url::to(['/post/index']);

// используя псевдоним "@posts", который определяется как "/post/index", /index.php?r=post%2Findex
echo Url::to(['@posts']);

Метод yii\helpers\Url::to() реализуется путем вызова методов createUrl() и createAbsoluteUrl() диспетчера URL. В следующих подразделах мы объясним, как настроить менеджер URL-адресов для настройки формата созданных URL-адресов.

Метод yii\helpers\Url::to() также поддерживает создание URL-адресов, не связанных с определенными маршрутами. Вместо того чтобы передавать массив в качестве его первого параметра, в этом случае вы должны передать строку. Например:

use yii\helpers\Url;

// запрашиваемый URL: /index.php?r=admin%2Fpost%2Findex
echo Url::to();

// URL с псевдонимом: http://example.com
Yii::setAlias('@example', 'http://example.com/');
echo Url::to('@example');

// абсолютный URL-адрес: http://example.com/images/logo.gif
echo Url::to('/images/logo.gif', true);

Помимо метода to(), вспомогательный класс yii\helpers\Url также предоставляет несколько других удобных способов создания URL. Например:

use yii\helpers\Url;

// URL главной страницы: /index.php?r=site%2Findex
echo Url::home();

// базовый URL-адрес, полезный, если приложение развернуто в подпапке веб-корня
echo Url::base();

// канонический URL-адрес запрашиваемого URL-адреса
// смотрим https://en.wikipedia.org/wiki/Canonical_link_element
echo Url::canonical();

// запомнить запрошенный URL и запросить его обратно в последующих запросах
Url::remember();
echo Url::previous();

Использование Pretty URLs

Чтобы использовать красивые URL-адреса, настройте компонент диспетчера url в конфигурации приложения следующим образом:

[
    'components' => [
        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'enableStrictParsing' => false,
            'rules' => [
                // ...
            ],
        ],
    ],
]

Свойство enablePrettyUrl является обязательным, поскольку он переключает красивый формат URL. Остальные свойства являются необязательными. Однако их конфигурация, показанная выше, наиболее часто используется.

  • showScriptName: это свойство определяет, должен ли сценарий входа быть включен в созданные URL. Например, вместо создания URL /index.php/post/100, установив это свойство в false, будет создан URL /post/100.
  • enableStrictParsing: это свойство определяет, следует ли разрешать синтаксический анализ запроса. Если включен строгий синтаксический анализ, входящий запрошенный URL должен соответствовать по крайней мере одному из правил, чтобы быть обработанным как действительный запрос, иначе будет выбрано исключение yii\web\NotFoundHttpException. Если строгий синтаксический анализ отключен, если ни одно из правил не соответствует запрошенному URL-адресу, часть информации о пути к URL-адресу будет считаться запрошенным маршрутом.
  • rules: это свойство содержит список правил, определяющих, как обрабатывать и создавать URL-адреса. Это основное свойство, с которым вы должны работать, чтобы создавать URL-адреса, формат которых удовлетворяет вашему конкретному требованию.

Правила для URL

Правило URL - это класс, реализующий интерфейс yii\web\UrlRuleInterface, обычно yii\web\UrlRule. Каждое правило URL состоит из шаблона, используемого для сопоставления информации о пути к URL-адресам, маршрута и нескольких параметров запроса. Правило URL-адреса может использоваться для разбора запроса, если его шаблон соответствует запрошенному URL-адресу. Правило URL-адреса может использоваться для создания URL-адреса, если его параметры маршрута и параметров запроса совпадают с указанными.

Когда включен довольно-таки формат URL, менеджер URL-адресов использует правила URL, объявленные в свойстве rules, для синтаксического анализа входящих запросов и создания URL-адресов. В частности, чтобы проанализировать входящий запрос, менеджер URL проверяет правила в том порядке, в котором они объявлены, и ищет первое правило, соответствующее запрошенному URL-адресу. Правило сопоставления затем используется для анализа URL-адреса в маршруте и связанных с ним параметрах. Аналогично, чтобы создать URL-адрес, менеджер URL-адреса ищет первое правило, которое соответствует данному маршруту и параметрам, и использует его для создания URL-адреса.

Вы можете настроить правила yii\web\UrlManager::$rules в качестве массива с ключами, являющимися шаблонами и значениями соответствующих маршрутов. Каждая пара шаблон-маршрут создает правило URL. Например, следующая конфигурация правил объявляет два правила URL. Первое правило соответствует URL posts и отображает их в post/index маршруте. Второе правило соответствует URL-адресу, соответствующему регулярному выражению post/(\d+), и отображает его в маршруте post/view и определяет параметр запроса с именем id.

'rules' => [
    'posts' => 'post/index',
    'post/<id:\d+>' => 'post/view',
]

Помимо объявления правил URL как пар шаблон-маршрут, вы также можете объявить их как конфигурационные массивы. Каждый массив конфигурации используется для настройки единого объекта правила URL. Это часто необходимо, если вы хотите настроить другие свойства правила URL. Например:

'rules' => [
    // ...другие URL правила...
    [
        'pattern' => 'posts',
        'route' => 'post/index',
        'suffix' => '.json',
    ],
]

По умолчанию, если вы не укажете опцию class для конфигурации правила, она примет класс по умолчанию yii\web\UrlRule, который является значением по умолчанию, определенным в yii\web\UrlManager::$ruleConfig.

Именованные параметры

Правило URL-адреса может быть связано с именованными параметрами запроса, указанными в шаблоне в формате <ParamName:RegExp>, где ParamName указывает имя параметра, а RegExp является необязательным регулярным выражением, используемым для соответствия значениям параметров. Если RegExp не указан, это означает, что значение параметра должно быть строкой без слэша.

Когда правило используется для разбора URL-адреса, оно заполняет соответствующие параметры значениями, соответствующими соответствующим частям URL-адреса, и эти параметры будут доступны в $ _GET позже компонентом приложения request. Когда правило используется для создания URL-адреса, оно принимает значения предоставленных параметров и вставляет их в тех местах, где объявлены параметры.

Давайте использовать некоторые примеры, чтобы проиллюстрировать, как работают именованные параметры. Предположим, мы объявили следующие три правила URL:

'rules' => [
    'posts/<year:\d{4}>/<category>' => 'post/index',
    'posts' => 'post/index',
    'post/<id:\d+>' => 'post/view',
]

Когда правила используются для разбора URL:

  • /index.php/posts анализируется в post/index маршруте с использованием второго правила;
  • /index.php/posts/2014/php анализируется в post/index маршрута, параметр year, значение которого равно 2014, и параметр category, значение которого является php с использованием первого правила;
  • /index.php/post/100 анализируется в маршруте post/view и параметре id, значение которого равно 100, используя третье правило;
  • /index.php/posts/php вызовет yii\web\NotFoundHttpException, когда yii\web\UrlManager::$enableStrictParsing истинно, потому что он не соответствует ни одному из шаблонов. Если yii\web\UrlManager::$enableStrictParsing имеет значение false (значение по умолчанию), в качестве маршрута будет возвращено сообщение о пути к posts/php. Это либо выполнит соответствующее действие, если оно существует, либо бросит yii\web\NotFoundHttpException в противном случае.

И когда правила используются для создания URL:

  • Url::to(['post/index']) создает /index.php/posts используя второе правило;
  • Url::to(['post/index', 'year' => 2014, 'category' => 'php']) создает /index.php/posts/2014/php используя первое правило;
  • Url::to(['post/view', 'id' => 100]) создает /index.php/post/100 используя третье правило;
  • Url::to(['post/view', 'id' => 100, 'source' => 'ad']) создает /index.php/post/100?source=ad с использованием третьего правила. Поскольку параметр-источник не указан в правиле, он добавляется в качестве параметра запроса в созданный URL-адрес.
  • Url::to(['post/index', 'category' => 'php']) создает /index.php/post/index?category=php не используя ни одно из правил. Обратите внимание, что поскольку ни одно из правил не применяется, URL-адрес создается просто добавлением маршрута в качестве информации о пути и всех параметров в качестве части строки запроса.

Параметрирование маршрутов

Вы можете вставлять имена параметров в маршрут правила URL. Это позволяет использовать правило URL для сопоставления нескольких маршрутов. Например, следующие правила встраивают controller и параметры action в маршруты.

'rules' => [
    '<controller:(post|comment)>/create' => '<controller>/create',
    '<controller:(post|comment)>/<id:\d+>/<action:(update|delete)>' => '<controller>/<action>',
    '<controller:(post|comment)>/<id:\d+>' => '<controller>/view',
    '<controller:(post|comment)>s' => '<controller>/index',
]

Чтобы разобрать URL /index.php/comment/100/update, будет применяться второе правило, которое устанавливает параметр controller как comment и action для обновления. Таким образом, маршрут <controller>/<action> разрешен как comment/update.

Аналогично, чтобы создать URL-адрес для comment/index маршрута, будет применяться последнее правило, которое создает URL /index.php/comments.

Значения параметров по умолчанию

По умолчанию все параметры, объявленные в правиле, являются обязательными. Если запрошенный URL не содержит определенного параметра или если URL-адрес создается без определенного параметра, правило не будет применяться. Чтобы сделать некоторые параметры необязательными, вы можете настроить свойство по умолчанию для правила. Параметры, перечисленные в этом свойстве, являются необязательными и будут принимать указанные значения, если они не предоставлены.

В следующем объявлении правила параметры page и tag являются необязательными и будут принимать значение 1 и пустую строку, соответственно, если они не предоставлены.

'rules' => [
    // ...другие правила...
    [
        'pattern' => 'posts/<page:\d+>/<tag>',
        'route' => 'post/index',
        'defaults' => ['page' => 1, 'tag' => ''],
    ],
]

Вышеупомянутое правило может использоваться для анализа или создания любого из следующих URL:

  • /index.php/postspage is 1, tag is ''.
  • /index.php/posts/2page is 2, tag is ''.
  • /index.php/posts/2/newspage is 2, tag is 'news'.
  • /index.php/posts/newspage is 1, tag is 'news'.

Без использования необязательных параметров вам нужно было бы создать 4 правила для достижения того же результата.

Правила с именами серверов

В шаблоны правил URL-адреса можно включать имена веб-серверов. Это в основном полезно, когда ваше приложение должно вести себя по-разному для разных имен веб-серверов. Например, следующие правила будут анализировать URL-адрес http://admin.example.com/login в маршруте admin/user/login и http://www.example.com/login на site/login.

'rules' => [
    'http://admin.example.com/login' => 'admin/user/login',
    'http://www.example.com/login' => 'site/login',
]

Вы также можете вставлять параметры в имена серверов для извлечения динамической информации из них. Например, следующее правило будет анализировать URL-адрес http://en.example.com/posts в post/index маршрута и параметре language=en.

'rules' => [
    'http://<language:\w+>.example.com/posts' => 'post/index',
]

Вы также можете использовать относительные шаблоны протокола, которые работают как для http, так и для https. Синтаксис такой же, как и выше, но пропущен http: part, например: '//www.example.com/login' => 'site/login'.

Суффикс URL

Вы можете добавить суффиксы к URL-адресам для различных целей. Например, вы можете добавить .html к URL-адресам, чтобы они выглядели как URL-адреса для статических HTML-страниц; Вы также можете добавить .json к URL-адресам, чтобы указать ожидаемый тип контента ответа. Вы можете достичь этой цели, настроив свойство yii\web\UrlManager::$suffix, например, следующее в конфигурации приложения:

[
    // ...
    'components' => [
        'urlManager' => [
            'enablePrettyUrl' => true,
            // ...
            'suffix' => '.html',
            'rules' => [
                // ...
            ],
        ],
    ],
]

Вышеупомянутая конфигурация позволит менеджеру URL-адресов распознавать запрошенные URL-адреса, а также создавать URL-адреса с расширением .html.

Иногда вы можете использовать разные суффиксы для разных URL-адресов. Это можно сделать, настроив свойство суффикса отдельных правил URL. Когда правило URL имеет этот набор свойств, он переопределит параметр суффикса на уровне менеджера URL-адресов. Например, следующая конфигурация содержит настраиваемое правило URL, которое использует вместо суффикса global .html .json его суффикс.

[
    'components' => [
        'urlManager' => [
            'enablePrettyUrl' => true,
            // ...
            'suffix' => '.html',
            'rules' => [
                // ...
                [
                    'pattern' => 'posts',
                    'route' => 'post/index',
                    'suffix' => '.json',
                ],
            ],
        ],
    ],
]

Методы HTTP

При внедрении API-интерфейсов RESTful обычно требуется, чтобы один и тот же URL подвергался синтаксическому разбору в разных маршрутах в соответствии с используемыми методами HTTP. Этого можно легко достичь, добавив префиксы поддерживаемых HTTP-методов к шаблонам правил. Если правило поддерживает несколько методов HTTP, разделите имена методов запятыми. Например, следующие правила имеют один и тот же шаблон post/<id:\d+> с поддержкой разных методов HTTP. Запрос PUT на post/100 будет разобран в post/update, а запрос GET на post/100 будет разобран в post/view.

'rules' => [
    'PUT,POST post/<id:\d+>' => 'post/update',
    'DELETE post/<id:\d+>' => 'post/delete',
    'post/<id:\d+>' => 'post/view',
]

Динамическое добавление правил

Правила URL могут динамически добавляться в менеджер URL. Это часто требуется для распространяемых модулей, которые хотят управлять своими собственными правилами URL. Чтобы динамически добавленные правила вступили в силу в процессе маршрутизации, их следует добавить на этапе начальной загрузки приложения. Для модулей это означает, что они должны реализовать yii\base\BootstrapInterface и добавить правила в метод bootstrap() следующим образом:

public function bootstrap($app)
{
    $app->getUrlManager()->addRules([
        // объявления правил здесь
    ], false);
}

Обратите внимание, что вы также должны указать эти модули в yii\web\Application::bootstrap(), чтобы они могли участвовать в процессе начальной загрузки.

Создание классов правил

Несмотря на то, что класс yii\web\UrlRule по умолчанию достаточно гибок для большинства проектов, бывают ситуации, когда вам нужно создавать собственные классы правил. Например, на веб-сайте автодилера вы можете поддержать формат URL-адреса типа /Manufacturer/Model, где оба Manufacturer и Model должны соответствовать некоторым данным, хранящимся в таблице базы данных. Класс правил по умолчанию не будет работать здесь, потому что он опирается на статически объявленные шаблоны.

Для решения этой проблемы мы можем создать следующий класс правил URL.

<?php

namespace app\components;

use yii\web\UrlRuleInterface;
use yii\base\Object;

class CarUrlRule extends Object implements UrlRuleInterface
{
    public function createUrl($manager, $route, $params)
    {
        if ($route === 'car/index') {
            if (isset($params['manufacturer'], $params['model'])) {
                return $params['manufacturer'] . '/' . $params['model'];
            } elseif (isset($params['manufacturer'])) {
                return $params['manufacturer'];
            }
        }
        return false; // this rule does not apply
    }

    public function parseRequest($manager, $request)
    {
        $pathInfo = $request->getPathInfo();
        if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {
            // check $matches[1] and $matches[3] to see
            // if they match a manufacturer and a model in the database.
            // If so, set $params['manufacturer'] and/or $params['model']
            // and return ['car/index', $params]
        }
        return false; // this rule does not apply
    }
}

И используйте новый класс правил в конфигурации yii\web\UrlManager::$rules:

'rules' => [
    // ...other rules...
    [
        'class' => 'app\components\CarUrlRule',
        // ...настройка других свойств...
    ],
]

Нормализация URL-адресов

UrlManager можно настроить на использование UrlNormalizer для работы с вариациями одного и того же URL-адреса, например, с или без концевой косой черты. Поскольку технически http://example.com/path и http://example.com/path/ - разные URL, обслуживание одного и того же контента для них может снизить рейтинг SEO. По умолчанию нормализатор свертывает последовательные слэши, добавляет или удаляет завершающие слэши в зависимости от того, имеет ли суффикс завершающий косой черт или нет, и перенаправляет нормализованную версию URL с помощью постоянного перенаправления. Нормализатор может быть настроен глобально для менеджера URL-адресов или индивидуально для каждого правила - по умолчанию каждое правило будет использовать нормализатор из менеджера URL-адресов. Вы можете установить UrlRule::$normalizer в false, чтобы отключить нормализацию для определенного правила URL.

Ниже приведен пример конфигурации UrlNormalizer:

'urlManager' => [
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'enableStrictParsing' => true,
    'suffix' => '.html',
    'normalizer' => [
        'class' => 'yii\web\UrlNormalizer',
        // использовать временное перенаправление вместо постоянного для отладки
        'action' => UrlNormalizer::ACTION_REDIRECT_TEMPORARY,
    ],
    'rules' => [
        // ...другие правила...
        [
            'pattern' => 'posts',
            'route' => 'post/index',
            'suffix' => '/',
            'normalizer' => false, // отключить нормализатор для этого правила
        ],
        [
            'pattern' => 'tags',
            'route' => 'tag/index',
            'normalizer' => [
                // не сворачивайте последовательные слэши для этого правила
                'collapseSlashes' => false,
            ],
        ],
    ],
]

Соображения производительности

При разработке сложного веб-приложения важно оптимизировать правила URL-адресов, чтобы сократить время на анализ запросов и создание URL-адресов.

Используя параметризованные маршруты, вы можете уменьшить количество правил URL, что может значительно повысить производительность.

При разборе или создании URL-адреса менеджер URL-адресов проверяет правила URL в том порядке, в котором они объявлены. Поэтому вы можете рассмотреть возможность изменения порядка правил URL-адресов, чтобы более конкретные и / или более часто используемые правила помещались перед менее используемыми.

Если некоторые правила URL используют один и тот же префикс в своих шаблонах или маршрутах, вы можете использовать yii\web\GroupUrlRule, чтобы они могли быть более эффективно проверены менеджером URL как группой. Это часто происходит, когда ваше приложение состоит из модулей, каждый из которых имеет свой собственный набор правил URL с идентификатором модуля в качестве их общих префиксов.