Технические детали Apache mod_rewrite
В этом документе рассматриваются некоторые технические детали mod_rewrite и сопоставления URL.
Фазы API
Сервер Apache HTTP обрабатывает запросы в несколько фаз. На каждой из этих фаз один или несколько модулей могут быть вызваны для обработки этой части жизненного цикла запроса. Фазы включают такие вещи, как перевод URL в имя файла, аутентификацию, авторизацию, контент и ведение журналов. (Это не исчерпывающий список.)
mod_rewrite действует на двух из этих фаз (или «крючках», как их часто называют), чтобы повлиять на то, как URL могут быть переписаны.
Во-первых, он использует крючок перевода URL в имя файла, который происходит после чтения HTTP-запроса, но до начала любой авторизации. Во-вторых, он использует крючок Fixup, который находится после фаз авторизации и после чтения файлов конфигурации по каталогам (.htaccess файлы), но перед вызовом обработчика контента.
Таким образом, после получения запроса и определения соответствующего сервера или виртуального хоста, движок переписывания начинает обработку всех mod_rewrite директив, появляющихся в конфигурации сервера (т.е. в основном файле конфигурации сервера и <Virtualhost> разделах). Это происходит на фазе перевода URL в имя файла.
Несколько шагов позже, после того, как были найдены окончательные каталоги данных, применяются директивы конфигурации по каталогам (.htaccess файлы и <Directory> блоки). Это происходит на фазе Fixup.
В каждом из этих случаев mod_rewrite переписывает REQUEST_URI либо на новый URL, либо на имя файла.
В контексте по каталогам (т.е. внутри .htaccess файлов и Directory блоков) эти правила применяются после того, как URL уже был переведён в имя файла. Из-за этого путь URL, с которым mod_rewrite изначально сравнивает RewriteRule директивы, является полным путём к файлу системы, переведённому в имя файла, с удалённым текущим путём каталогов (включая конечный слэш) с начала.
Для иллюстрации: если правила находятся в /var/www/foo/.htaccess, и обрабатывается запрос /foo/bar/baz, выражение типа ^bar/baz$ будет совпадать.
Если подстановка выполняется в контексте по каталогам, высылается новый внутренний подзапрос с новым URL, который перезапускает обработку фаз запроса. Если подстановка является относительным путём, RewriteBase директива определяет префикс пути URL, добавляемый к подстановке. В контексте по каталогам необходимо позаботиться о создании правил, которые в конечном итоге (в какой-то будущей «итерации» обработки переписывания по каталогам) не будут выполнять подстановку, чтобы избежать циклов. (См. RewriteLooping для более подробного обсуждения этой проблемы.)
Из-за этого дальнейшего изменения URL в контексте по каталогам вам нужно будет по-разному создавать правила переписывания в этом контексте. В частности, помните, что ведущий путь каталога будет удалён из URL, который увидят ваши правила переписывания. Рассмотрите примеры ниже для дальнейшего разъяснения.
| Расположение правила | Правило |
|---|---|
| Раздел VirtualHost | RewriteRule "^/images/(.+)\.jpg" "/images/$1.gif" |
| Файл .htaccess в корневом каталоге документов | RewriteRule "^images/(.+)\.jpg" "images/$1.gif" |
| Файл .htaccess в каталоге images | RewriteRule "^(.+)\.jpg" "$1.gif" |
Для ещё более глубокого понимания того, как mod_rewrite обрабатывает URL в различных контекстах, вы должны обратиться к записям журнала, созданным во время переписывания.
Обработка набора правил
Теперь, когда mod_rewrite срабатывает в этих двух фазах API, он считывает настроенные наборы правил из своей структуры конфигурации (которая сама была создана либо при запуске для контекста сервера, либо во время обхода каталогов ядра Apache для контекста по каталогам). Затем движок переписывания URL запускается с набором правил (одним или несколькими правилами вместе с их условиями). Работа самого движка переписывания URL абсолютно одинакова для обоих контекстов конфигурации. Отличается только обработка конечного результата.
Порядок правил в наборе правил важен, потому что движок переписывания обрабатывает их в особом (и не очень очевидном) порядке. Вот правило: движок переписывания циклически проходит по правилам набора правило за правилом (RewriteRule директивы), и когда определённое правило соответствует, он по желанию циклически проходит по существующим соответствующим условиям (RewriteCond директивы). По историческим причинам условия указываются первыми, и поэтому поток управления немного усложняется. Смотрите рисунок 1 для более подробных сведений.
Рисунок 1:Поток управления набором правил переписывания
Сначала URL сопоставляется с шаблоном каждого правила. Если это не удалось, mod_rewrite немедленно прекращает обработку этого правила и продолжает с следующим. Если шаблон соответствует, mod_rewrite ищет соответствующие условия правила (директивы RewriteCond, отображаемые непосредственно над RewriteRule в конфигурации). Если их нет, он подставляет URL новым значением, которое построено из строки Замены, и продолжает цикл по правилам. Но если условия существуют, он начинает внутренний цикл для их обработки в указанном порядке. Для условий логика отличается: мы не сопоставляем шаблон с текущим URL. Вместо этого мы сначала создаём строку TestString, расширяя переменные, обратные ссылки, поиск по картам и т.д., а затем пытаемся сопоставить CondPattern с ней. Если шаблон не совпадает, весь набор условий и соответствующее правило не проходят. Если шаблон совпадает, обрабатывается следующее условие, пока не закончатся условия. Если все условия соответствуют, продолжается обработка с заменой URL на Замену.
© 2018 The Apache Software Foundation
Licensed under the Apache License, Version 2.0.
https://httpd.apache.org/docs/2.4/en/rewrite/tech.html