Apache. Магия mod_rewrite

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

Об этом замечательном модуле сервера Apache  и пойдет речь в этом посте

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

Чаще всего правила перенаправления используются в файле .htaccess. Например, я в большинстве своих проектов использую вот такой небольшой набор правил:

Данный набор правил перенаправляет все запросы, за исключением запросов на статические файла, на скрипт приложения. А приложение уже само решает что делать с тем или иным запросом. Очень удобно, правил пало все понятно:) Но иногда требуется ввести дополнительные правила, и тут без основ никак. Давайте разберемся как же на самом деле работает mod_rewrite.

Что за магия скрывается в RewriteRule?

На самом деле никакой магии нет. Чтобы пропала вся магичность этого правила надо в первую очередь понять, с чем работает RewriteRule.

Когда только начинаешь работать с mod_rewrite кажется, что RewriteRule работает со ссылками, но это не так! Это первое и главное заблуждение. На самом деле в RewriteRule передается путь до запрошенного файла. Такое поведение объясняется архитектурой apache, исходный путь к моменту обработки в mod_rewrite может быть уже изменен другими модулями и не совпасть с исходной ссылкой.

И так, в mod_rewrite передается абсолютный путь до запрошенного файла.Кроме того, зная путь к .htaccess, mod_rewrite отрезает от абсолютного пути часть до .htaccess и передает его в RewriteRule.

Важно понимать, что RewriteRule не обрабатывает имя сайта, параметров переданных в скрипт, да и путь не весь, если .htaccess находится не в корне. И строка, передаваемая на обработку никогда не начинается с /.

Далее переданный путь RewriteRule обрабатывает как обыкновенную строку!!! Вот и нет никакой магии:) Этими делами занимается RewriteCond.

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

Чтобы наглядно проиллюстрировать это рассмотрим следующий пример:

Видим, что RewriteRule совершенно не важно какую строку обрабатывать. Однако стоит помнить, что RewriteRule заточен для обработки ссылок, поэтому будет специфично реагировать на строки начинающиеся скажем с "http://", "ftp://" (для таких строку будет запомнен внешний редирект), или на символ ? (в этом случае он посчитает символы справа от ? аргументами, которые нужно будет подставить к запросу). Самое главное - теперь ясно, что никакой магии нет.

Итак, все RewriteRule обработаны. Теперь работает RewriteBase. !!!RewriteBase работает именно после выполнения всех RewriteRule, даже если находится выше них!!!

Встречаем RewriteBase.

RewriteBase проверяет, какой получился адрес. Если адрес относительный и изменился, то приписывает себя к адресу слева.

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

RewriteBase выполняется после всех преобразований и не может быть выполнен между RewriteRule.

Абсолютным путем считается строка начинающаяся с протокола, например, http://...., или строка начинающаяся с символа "/", например "/news/index.php"

абсолютный путь, то RewriteBase ничего не делает.

Обычно, после начального знакомства с mod_rewrite приобретается привычка: в каждый .htaccess добавляем «RewriteBase /», все перенаправления начинать со слеша: «RewriteRule news.html /index.php?controller=news».

Что, если я не укажу RewriteBase? По умолчанию Apache сделает его равным абсолютному пути в файловой системе до .htaccess (например, /var/www/news/). Некорректность такого предположения Apache проявляется на внешних относительных редиректах.

Рассмотрим пример:

Итак, все вышеперечисленные преобразования выполнены. Апачи отдает запрошенный файл пользователю? НЕТ!!! Так как получившийся запрос изменил исходный, то теперь запрос будет обрабатываться еще раз.

Флаг [L]

mod_rewrite будет обрабатывать запрос до тех пор, пока он меняется. Останов произойдет только, если запрос при очередной обработке не изменился!

Самое главное - флаг [L] не может это остановить!

Такое поведение Apache объясняется тем, что в процессе изменения запроса он мог быть перенаправлен в другую директорию. В ней может быть собственный .htaccess, который не участвовал в предыдущей обработке запроса. В этом же новом .htaccess могут быть правила, которые влияют на обработку запроса — как правила mod_rewrite, так и правила других модулей. Чтобы корректно обработать эту ситуацию, Apache должен запустить весь цикл обработки заново.

Упс. А зачем же тогда флаг [L]? Флаг [L] останавливает текущую итерацию в этом процессе. И если запрос был изменен Apache запустит обработку .htaccess еще раз!

Последний пример приведет к ошибке "Internal Server Error".

Воизбежание таких ошибок, нужно пользоваться флагом флаг [L] только при необходимости. А именно: 1) используется внешний редирект — [L,R=301] или [L,R=302]. В случае внешнего редиректа дальнейшая обработка запроса нежелательна, и ее лучше остановить.2) Когда в .htaccess есть зацикливание, от которого не избавиться, и обработку запроса mod_rewrite'ом нужно принудительно прекратить.

Флаг [R]

Внутренний редирект - это когда просто меняется путь до запрошенного файла и пользователь думает, что получил файл, который запросил изначально.При внешнем же редиректе вместо содержимого файла возвращается статус ответа 301 или 302 и указывается фдрес, где пользователь может получить запрошенный файл. Если Apache встречается указанный флаг, то он себе помечает, что по завершении обработки всех запросов нужно выполнить внешний редирект. Еще раз: флаг [R] не останавливает обработку .htaccess! Это видно, скажем по третьему примеру, расположенному выше.

Но если уж вы решили сделать внешний редирект, то вряд ли вам нужна дальнейшая обработка запроса. Поэтому при указании флага [R] рекомендуют дополнительно указывать флаг [L].

Во втором случае Apache сам сообразит что нужно сделать внешний редирект.

Флаг [QSA]

RewriteRule может менять не только путь к файлу, ной get-параметры запроса.

Когда RewriteRule встречает занк ? во втором аргументе, то понимает: 1) заменить текущую обрабатываемую строку на выражение до знака "?";2) изменит QUERY_STRING.

Если флаг [QSA] не указан, то QUERY_STRING будет полностью заменена выражением справа от "?". Если флаг [QSA] указан, то выражение после "?" будет добавлено в начало QUERY_STRING.

RewriteCond

Условия RewriteCond указываются непосредственно перед соответствующим RuleRewrite. ОДнако шибочно полагать, что они срабатывают первыми!

На самом деле сначала Apache проверяет запрос на соответствие регулярному выражению в RewriteRule и если найдено соответствие - то вычисляются RewriteCond. Таким образом, добавление лишних RewriteCond никак не может положительно сказаться на производительности обработфи .htaccess.

Таким образом, если у вас трехкилометровое регулярное выражение в RewriteRule и вы задумались о производительности, используя RewriteCond, то знайте - толку не будет. В этом случае лучше использовать флаги RewriteRule [C] или [S], чтобы пропустить более сложное правило, если более простые проверки не сработали.

Надеюсь после этой заметки у вас стало меньше вопросов по mod_rewrite!

Нет комментариев.
Добавить комментарий
Вам необходимо включить показ изображений в браузере для того чтобы увидеть код

Дайте нам знать, что вы - живой человек. Для нас это важно!
Кликните, если плохо видно

Прежде чем высказать свое мнение, прочитайте пожалуйста: правила

Рейтинг@Mail.ru