Академия mod_rewrite. Урок 2: флаги [R], [L], [QSA], [NC], [F], [G] и другие

Флаги RewriteRule управляют тем, что именно происходит после срабатывания правила: редирект или перезапись, постоянный или временный, сохранять ли строку запроса, блокировать ли доступ. В этом уроке разберём все ключевые флаги с примерами.

Урок 2 из 5 · ← предыдущий | следующий → · оглавление курса

Зачем нужны флаги

Флаги записываются в квадратных скобках через запятую после подстановки: RewriteRule паттерн подстановка [флаг1,флаг2]. Они определяют:

  • тип ответа — внутренняя перезапись, редирект (и с каким кодом), блокировка;
  • что делать со строкой запроса (?param=value);
  • чувствительность к регистру и кодирование символов;
  • поведение при цепочках правил.

Флаги редиректа: R=301, R=302, R=307, R=308

Флаг [R] превращает правило во внешний редирект — сервер отвечает кодом 30x и браузер переходит по новому адресу. Без числа — код 302 (временный).

  • [R=301]постоянный редирект. Браузер и поисковики запоминают новый адрес. Используйте при переезде страниц навсегда.
  • [R=302]временный редирект. Поисковики продолжают индексировать старый адрес. Используйте для временных акций, A/B-тестов.
  • [R=307] — временный, сохраняет метод запроса (POST остаётся POST). Для форм и API.
  • [R=308] — постоянный, сохраняет метод запроса (Apache 2.4.26+).

Пример постоянного редиректа с сохранением пути:

.htaccessкопировать
RewriteEngine On
RewriteRule ^old-section/(.*)$ /new-section/$1 [R=301,L]

Важно: подстановка при [R] должна быть абсолютным путём (начинаться с /) или полным URL. Относительная подстановка с [R] приводит к непредсказуемому результату.

[L] и [END]: остановить обработку

[L] — «last». Останавливает обработку правил в текущем проходе. Но в контексте .htaccess Apache перезапускает весь набор правил с новым URL, если он изменился. Поэтому [L] не гарантирует, что другие правила не применятся.

[END] — полная остановка (Apache 2.4+). Предотвращает перезапуск набора правил. Используйте, когда нужно гарантированно остановить обработку.

Типичная ошибка: правило с [L] делает внутреннюю перезапись, а ниже есть фронт-контроллер. После прохода Apache запускает набор заново и фронт-контроллер срабатывает на уже переписанный URL. Решение — правильный порядок правил или замена [L] на [END] там, где это уместно.

[QSA] и [QSD]: строка запроса

Строка запроса (?id=5&page=2) по умолчанию ведёт себя так: если в подстановке есть ? — она заменяет исходную строку запроса; если ? нет — исходная сохраняется.

[QSA] («query string append») — добавить исходную строку запроса к новой. Полезно, когда подстановка уже содержит параметры и нужно сохранить дополнительные:

.htaccessкопировать
RewriteEngine On
RewriteRule ^product/(\d+)$ /catalog.php?id=$1 [L,QSA]

Запрос /product/42?color=red будет обработан как /catalog.php?id=42&color=red.

[QSD] («query string discard», Apache 2.4+) — отбросить исходную строку запроса. Полезно при редиректах на чистые URL.

[NC] и [NE]: регистр и кодирование

[NC] («nocase») — сопоставлять паттерн без учёта регистра. Например, паттерн ^image\.PNG$ с [NC] сработает и на image.png, и на image.PNG, и на IMAGE.Png.

Используйте осторожно: [NC] может «поглотить» больше запросов, чем вы планировали. Лучше явно указывать расширения в нижнем регистре и не полагаться на [NC] без необходимости.

[NE] («noescape») — не URL-кодировать спецсимволы в подстановке. Нужен, когда подстановка содержит символы ?, #, % и они должны остаться как есть, а не быть закодированы.

[F] и [G]: блокировка и Gone

[F] («forbidden») — вернуть ответ 403 Forbidden. Используется для блокировки доступа к файлам, каталогам, по User-Agent. Подстановку обычно пишут как - (не менять URL):

.htaccessкопировать
RewriteEngine On
RewriteRule \.(sql|bak|log)$ - [F,L]

[G] («gone») — вернуть ответ 410 Gone. Означает «ресурс удалён навсегда». Поисковики, получив 410, быстрее убирают страницу из индекса, чем при 404. Используйте для намеренно удалённых страниц:

.htaccessкопировать
RewriteEngine On
RewriteRule ^promo-2019/?$ - [G,L]

[C] и [S=N]: цепочки и пропуск

[C] («chain») — «сцепить» это правило со следующим. Следующее правило выполнится только если текущее сработало. Если текущее не сработало — следующее (и вся цепочка) пропускается. Полезно для последовательных преобразований.

[S=N] («skip») — при срабатывании правила пропустить следующие N правил. Это что-то вроде goto: позволяет реализовать ветвление без лишних условий.

.htaccessкопировать
RewriteEngine On
# Если файл существует — пропустить 1 следующее правило
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [S=1]
# Это правило сработает только если файл НЕ существует
RewriteRule ^ index.php [L]

Попробуй сам

Откройте тестер RewriteRule и поэкспериментируйте с флагами: попробуйте добавить и убрать [QSA], заменить [R=301] на [R=302], посмотреть разницу в трассировке. Особенно полезно сравнить поведение с [L] и без него.

Упражнения

  1. Напишите временный редирект (302) со старого раздела /promo/ на /sales/.
    Подсказка: [R=302,L] или просто [R,L] — по умолчанию 302.
    Проверьте в тестере RewriteRule.
  2. Напишите правило с [QSA]: перезаписать /item/5 в /item.php?id=5, при этом сохранив любые дополнительные параметры вроде ?color=red.
    Подсказка: используйте группу захвата (\d+) для числа.
    Проверьте в тестере RewriteRule.
  3. Вернуть 410 Gone на запросы к /promo-2019 и /promo-2020.
    Подсказка: паттерн с альтернативой (2019|2020) и флаг [G,L].
    Проверьте в тестере RewriteRule.
  4. Почему флаг [NC] иногда опасен? Приведите пример ситуации, когда он может захватить лишнее.
    Подсказка: паттерн ^admin с [NC] сработает и на /Admin, и на /ADMIN.

Что дальше

В уроке 3 разберём RewriteCond — условия перед правилом, серверные переменные %{HTTP_HOST}, %{HTTPS}, %{REQUEST_URI} и специальные проверки файловой системы. Именно там живёт настоящая мощь mod_rewrite.