Модуль mod_rewrite

mod_rewrite – модуль веб-сервера Apache, предназначенный для преобразования URL. Работает «на лету», преобразуя запрошенный URL по заданным правилам с использованием регулярных выражений. При этом правила преобразований могут быть заданы как для веб-сервера в целом (в файле конфигурации httpd.conf или включаемых файлах), так и в контексте отдельной директории (в файле локальной конфигурации .htaccess). Кроме шаблонов правил, задаются также и условия их выполнения, в результате получается очень гибкий и мощный механизм преобразования. В условиях используются переменные окружения Apache, что позволяет управлять подменой не только URI, но и имени хоста, реагировать на браузер (или поискового бота), переадресовывать запрос в другой домен, обрабатывать ошибочные запросы и многое другое.

Применение mod_rewrite

Применение модуля в практике сайтостроительства вполне соответствует широко известному «принципу 20×80»: 20% функций используются в 80% случаев, на остальные 80% функций приходится 20% использования. Это не значит, что в модуле много ненужного, это говорит о его широких возможностях. В основном модуль применяют для переадресации запросов и обработки псевдостатических ссылок, реже – для фильтрации и отсечения некорректных запросов.

Псевдостатические ссылки

Использование правил mod_rewrite для обработки псевдостатических ссылок стало фактическим стандартом в разработке «движков» сайта. Замена ссылки на скрипт с параметрами запроса ссылкой на статический файл (или директорию) требует обратной замены в момент обращения по этой ссылке. Модуль по заданным правилам разбирает URI и «реконструирует» подлинную ссылку на файл скрипта и параметры вызова. В результате скрипт (или набор скриптов) вызываются веб-сервером на обработку в естественном для скриптов формате, но в браузере посетителя никаких переадресаций и смены ссылки не происходит.

Например, скрипт галереи принимает в качестве параметров идентификатор раздела (строку символов латинского алфавита) — id и номер страницы в разделе — page. А в ссылках, которые он дает для навигации, значения параметров даны через дефис и добавлено расширение html. Ссылка на вторую страницу выставки чайников выглядит как /teapot-p2.html, а для получения этой страницы нужно вызвать скрипт index.php с параметрами id=teapot&page=2.

RewriteEngine on
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ([a-z]+)\-p([0-9]+)\.html$ index.php?id=$1&page=$2 [L]

Очень часто используется другой вариант разбора псевдостатики, когда ссылки разбирает «главный» скрипт движка. Но и в этом случае все равно требуется хотя бы одно правило для mod_rewrite, чтобы передать любой запрос в обработку именно этому скрипту.

RewriteEngine on
RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php [L]

По этому правилу любой запрос к несуществующему файлу передается скрипту index.php — а этот скрипт должен разобрать и обработать запрошенный URI.

Переадресация запросов

Переадресация запросов (перенаправление) может быть реализована как внутри одного домена, так и между разными доменами. При этом код статуса HTTP можно задавать любой, в зависимости от целей перенаправления.

Как сделать переадресацию домена (.htaccess при смене домена, склейка)

Для «склейки» доменов, например, может быть использован такой набор правил:

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} .
RewriteCond %{HTTP_HOST} !^new-domain\.com [NC]
RewriteRule (.*) http://new-domain.com/$1 [R=301,L] 

для HTTPS (SSL) будет так:

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} .
RewriteCond %{HTTP_HOST} !^new-domain\.com [NC]
RewriteRule (.*) https://new-domain.com/$1 [R=301,L] 

Этот вариант наиболее универсальный и в большинстве случаев лучше отдать ему предпочтение. Условие преобразования в этом случае означает «если имя запрошенного домена не начинается с new-domain.com». Тем самым набор правил привязан только к тому домену, в который будут перенаправляться все запросы. Сколько и каких доменов являются алиасами — совершенно неважно, все обращения к ним будут перенаправлены в один домен. Правило преобразования целиком подставляет «внутренний» URI, направляя клиента на тот же адрес внутри домена.

Другой вариант:

RewriteEngine on
RewriteBase /

RewriteCond %{HTTP_HOST} old-domain.com
RewriteRule (.*) http://new-domain.com/$1 [R=301,L]

В этом примере проводится перенаправление запроса к old-domain.com в домен new-domain.com с сохранением внутреннего URI, то есть, фактически обрабатывается запрос к любой странице сайта с перенаправлением по тому же внутреннему адресу в другом домене. Это правила для случая «переезда» сайта в другой домен с сохранением всей структуры внутренних ссылок.
Строка RewriteCond задает условие преобразования: если обратились к хосту, имя которого содержит old-domain.com. Обратите внимание, здесь нет меток ^ («начинается с») и $ («оканчивается на»), поэтому условие истинно и для old-domain.com, и для www.old-domain.com.

Поскольку базой преобразования (RewriteBase) назначена корневая директория сайта, правило RewriteRule принимает как входной шаблон всю относительную ссылку (от корня сайта, исключая символ корня /). В этом качестве оно берет любую цепочку любых символов, которую содержит URI, и подставляет ее в выходной шаблон на место сочетания символов $1. После чего проводится переадресация запроса на сформированный адрес: Apache выдает посетителю в заголовке HTTP статус 301 («Moved Permanently»), и в поле Location: заголовка помещает сформированный адрес.

Таким образом, запрос http://www.old-domain.ru/anydir/anyfile.php?id=314 будет перенаправлен на адрес http://new-domain.ru/anydir/anyfile.php?id=314

mod_rewrite (.htaccess) для выбора канонической формы доменного имени

Другой распространенный случай — использование переадресации для выбора канонической (основной) формы доменного имени (с www или без www). Например, для выбора домена www.domain.com нам нужен такой набор правил:

RewriteEngine on
RewriteBase /

RewriteCond %{HTTP_HOST} !^www
RewriteRule (.*) http://www.domain.com/$1 [R=301,L]

В этом случае условие преобразования буквально означает «если имя хоста не начинается с www». При выполнении этого условия (например, запрошен http://domain.com/anyfile.html) сработает правило, которое подставит внутренний URI в шаблон и перенаправит по тому же адресу в домене с www — http://www.domain.com/anyfile.html.

Если вы хотите избавиться о www в адресе сайта, то можно применить в .htaccess такой код:

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} .
RewriteCond %{HTTP_HOST} !^domain\.com [NC]
RewriteRule (.*) http://domain.com/$1 [R=301,L] 

Где domain.com - домен вашего сайта. Данное условие получает переменную HTTP_HOST (имя домена), сравнивает с требуемым (!^domain\.com [NC]), если условие выполняется и HTTP_HOST не равно domain.com, то переадресовываем на наш домен domain.com.

Каноническое отображение url каталога

Как сделать редирект названия каталога без слеша на название со слешем ( site.info/url site.info/url/ )?

Всё просто:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*\..*|.*/)$
RewriteRule ^(.*)$ /$1/ [R=301,L]

Не каноническое отображение url каталога

Бывают такие случаи, когда требуется, чтобы не было слеша в конце url (хотя это не есть правильно), для этого необходимо сделать редирект такого плана site.info/url/ site.info/url Все просто:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^(.+)/$
RewriteRule ^(.+)/$ /$1 [R=301,L]

Запрет для некорректных роботов

От поисковых роботов нам прятать нечего. Но, как известно, «любительских» и спамерских ботов становится всё больше. Многие из них не поддерживают стандарт исключений и даже не запрашивают файл robots.txt. Зато с гордостью предъявляют своё название (User-agent). Толку от такого робота нам никакого, только лишняя нагрузка на сервер. Мы можем закрыть доступ такому некорректному боту простым правилом:

RewriteEngine on
RewriteBase /

RewriteCond %{HTTP_USER_AGENT} Vasin-Robot
RewriteRule (.*) - [F,L]

Условие проверяет наличие в переменной окружения HTTP_USER_AGENT строки Vasin-Robot. Если такая строка обнаружена, сработает правило преобразования. Оно очень простое: по любому запросу ничего не пеобразовывать, выдать HTTP-заголовок с кодом статуса «403 Forbidden». Васин робот получит этот заголовок вместо любого запрошенного документа, никакие другие действия выполняться не будут.

Мифы и заблуждения

К сожалению, широкие возможности mod_rewrite порождают ошибочное представление о его «всемогуществе». Очень часто на форумах задают глупые вопросы вроде «как с помощью mod_rewrite отдавать 404 на ошибочные запросы?». Этот модуль ничего не «знает» о движке сайта, особенностях его работы, структуре данных – он умеет только работать с URI по заранее определенным правилам с применением регулярных выражений POSIX. Больше ничего. Чудес не бывает.

Настоятельно не рекомендуется брать какие попало правила и дописывать их к себе в .htaccess, если не понимаете:

  1. как они работают
  2. как они взаимодействуют с тем, что уже есть у вас в .htaccess

Такой подход напоминает самолечение по принципу «если соседу эти таблетки помогли от головной боли, то может быть, и мой геморрой вылечат». Во многих случаях механическое повторение возможно только с тем же самым движком (и с теми же самыми настройками).

Порядок правил

Это на первый взгляд не очевидно, но порядок следования правил для mod_rewrite очень важен. Условия и правила проверяются в том порядке, в каком они записаны. При первом же совпадении URL с условием и шаблоном правила будет запущена обработка запроса по этому правилу. Поэтому всю совокупность правил нужно рассматривать как единое целое и определять примерно такой порядок следования:

  1. правила блокировок и запретов
  2. правила перенаправления
  3. правила подмены динамических URL

Если вы разместите правила для перенаправления ниже, чем правила преобразования URL, то во многих случаях до перенаправления просто «не дойдет ход». То же самое и с правилами для блокировки доступа.

Ссылки

Статья не претендует на полное раскрытие темы mod_rewrite — тем более, что тема давно раскрыта другими. И сделаны отличные переводы на русский язык. Изучать mod_rewrite рекомендуется не по «сборникам рецептов для .htaccess», собранных не всегда грамотными людьми, а по этим источникам:

mod_rewrite.txt · создано: 2010/06/09 05:53 — Zanuda · Последние изменения: 2015/10/31 00:29 — rech
Наверх
Driven by DokuWiki