| Раздел 4. Руководство по перезаписи URL
Пункт 36. Использование mod_rewrite для перенаправления и переназначения URL-адресов Этот документ дополняет mod_rewrite
справочную документацию. В нем описывается, как вы можете использовать mod_rewrite для перенаправления и переназначения запроса. Это включает в себя множество примеров общего использования mod_rewrite, включая подробное описание того, как каждый из них работает.
Обратите внимание, что многие из этих примеров не будут работать без изменений в вашей конкретной конфигурации сервера, поэтому важно, чтобы вы их поняли, а не просто вырезали и вставляли примеры в свою конфигурацию.
От старого к новому (внутренний)
- Описание:
-
Предположим, мы недавно переименовали страницу
foo.html в bar.html и теперь хотим предоставить старый URL-адрес для обратной совместимости. Однако мы хотим, чтобы пользователи старого URL даже не узнавали, что страницы были переименованы — то есть мы не хотим, чтобы адрес менялся в их браузере.
- Решение:
-
Мы переписываем старый URL-адрес на новый внутри с помощью следующего правила:
RewriteEngine включен
RewriteRule "^ /foo \.html$" " /bar .html" [PT]
Переписывание со старого на новое (внешнее)
- Описание:
-
Предположим снова, что мы недавно переименовали страницу
foo.html в bar.html и теперь хотим предоставить старый URL-адрес для обратной совместимости. Но на этот раз мы хотим, чтобы пользователи старого URL-адреса получали подсказку о новом, т.е. поле Location в их браузерах также должно измениться.
- Решение:
-
Мы принудительно перенаправляем HTTP на новый URL-адрес, что приводит к смене браузеров и, следовательно, к просмотру пользователями:
RewriteEngine включен
RewriteRule "^ /foo \.html$" " bar .html" [ R ]
- Обсуждение
-
В этом примере, в отличие от внутреннего примера выше, мы можем просто использовать директиву Redirect. mod_rewrite использовался в предыдущем примере, чтобы скрыть перенаправление от клиента:
Перенаправление "/foo.html" "/bar.html"
Ресурс перемещен на другой сервер
- Описание:
-
Если ресурс переместился на другой сервер, вы можете захотеть, чтобы URL-адреса некоторое время продолжали работать на старом сервере, пока люди обновляют свои закладки.
- Решение:
-
Вы можете использовать mod_rewrite для перенаправления этих URL-адресов на новый сервер, но вы также можете рассмотреть возможность использования директивы Redirect или RedirectMatch.
#С mod_rewrite
RewriteEngine включен
RewriteRule "^/docs/(.+)" "http://new.example.com/docs/$1" [R,L]
#С перенаправлением
RedirectMatch "^/docs/(.*)" "http://new.example.com/docs/$1"
#С перенаправлением
Перенаправить "/docs/" "http://new.example.com/docs/"
От статики к динамике
- Описание:
-
Как мы можем преобразовать статическую страницу
foo.html в динамический вариант
foo.cgi бесшовным способом, т.е. без уведомления браузера/пользователя.
- Решение:
-
Мы просто переписываем URL-адрес CGI-скрипта и заставляем обработчик быть cgi-скриптом , чтобы он выполнялся как CGI-программа. Таким образом, внутренний запрос /~quux/foo.html
приводит к вызову
/~quux/foo.cgi .
RewriteEngine включен
RewriteBase "/~quux/"
RewriteRule "^foo\.html$" "foo.cgi" [H= cgi-script ]
Обратная совместимость для изменения расширения файла
- Описание:
-
Как мы можем сделать URL-адреса обратно совместимыми (все еще существующими виртуально) после перехода document.YYYY
на document.XXXX , например, после перевода группы .html файлов на .php ?
- Решение:
-
Мы переписываем имя на его базовое имя и проверяем наличие нового расширения. Если он существует, мы берем это имя, в противном случае мы переписываем URL-адрес в исходное состояние.
# набор правил обратной совместимости для
# перезаписываем document.html в document.php
# когда и только когда существует document.php
<Каталог "/var/www/htdocs">
RewriteEngine включен
Переписать базу "/var/www/htdocs"
RewriteCond "$1.php" -f
RewriteCond "$1.html" !-f
Правило перезаписи "^(.*).html$" "$1.php"
</Каталог>
- Обсуждение
-
В этом примере используется часто упускаемая возможность mod_rewrite, использующая порядок выполнения набора правил. В частности, mod_rewrite оценивает левую часть RewriteRule до того, как оценивает директивы RewriteCond. Следовательно, $1 уже определен к моменту оценки директив RewriteCond. Это позволяет нам проверить существование исходного ( document.html ) и целевого ( document.php ) файлов, используя одно и то же базовое имя файла.
Этот набор правил предназначен для использования в контексте каждого каталога (в блоке <Directory> или в файле .htaccess), чтобы при проверке
-f учитывался правильный путь к каталогу. Возможно, вам потребуется установить RewriteBase директиву, чтобы указать базу каталогов, в которой вы работаете.
Канонические имена хостов
- Описание:
- Целью этого правила является принудительное использование определенного имени хоста вместо других имен хостов, которые могут использоваться для доступа к тому же сайту. Например, если вы хотите принудительно использовать www.example.com вместо
example.com , вы можете использовать вариант следующего рецепта.
- Решение:
-
Самый лучший способ решить эту проблему вообще не включает mod_rewrite, а скорее использует директиву, Redirect
помещенную в виртуальный хост для неканонических имен хостов.
<Виртуальный хост *:80>
Нежелательное имя сервера.example.com
Псевдоним сервера example.com notthis.example.com
Перенаправление "/" "http://www.example.com/"
</ виртуальный хост>
<Виртуальный хост *:80>
Имя сервера www.example.com
</ виртуальный хост>
В качестве альтернативы вы можете выполнить это с помощью
<If>
директивы:
<Если "%{HTTP_HOST} != 'www.example.com'">
Перенаправление "/" "http://www.example.com/"
</Если>
Или, например, чтобы перенаправить часть вашего сайта на HTTPS, вы можете сделать следующее:
<Если "%{SERVER_PROTOCOL} != 'HTTPS'">
Перенаправить "/admin/" "https://www.example.com/admin/"
</Если>
Если по какой-либо причине вы все еще хотите использовать mod_rewrite
— если, например, вам нужно, чтобы это работало с большим набором RewriteRules — вы можете использовать один из рецептов ниже.
Для сайтов, работающих на порту, отличном от 80:
RewriteCond "%{HTTP_HOST}" "!^www\.example\.com" [NC]
RewriteCond "%{HTTP_HOST}" "!^$"
RewriteCond "%{SERVER_PORT}" "!^80$"
RewriteRule "^/?(.*)" "http://www.example.com:%{SERVER_PORT}/$1" [L,R,NE]
И для сайта, работающего на порту 80
RewriteCond "%{HTTP_HOST}" "!^www\.example\.com" [NC]
RewriteCond "%{HTTP_HOST}" "!^$"
RewriteRule "^/?(.*)" "http://www.example.com/$1" [L,R,NE]
Если вы хотите сделать это в общем для всех доменных имен, то есть если вы хотите перенаправить example.com на
www.example.com для всех возможных значений
example.com , вы можете использовать следующий рецепт:
RewriteCond "%{HTTP_HOST}" "!^www\." [НЗ]
RewriteCond "%{HTTP_HOST}" "!^$"
RewriteRule "^/?(.*)" "http://www.%{HTTP_HOST}/$1" [L,R,NE]
Эти наборы правил будут работать либо в вашем основном файле конфигурации сервера, либо в .htaccess файле, размещенном в файле DocumentRoot server.
Поиск страниц более чем в одном каталоге
- Описание:
-
Конкретный ресурс может существовать в одном из нескольких мест, и мы хотим искать в этих местах ресурс, когда он запрашивается. Возможно, недавно мы изменили структуру каталогов, разделив содержимое на несколько мест.
- Решение:
-
Следующий набор правил выполняет поиск в двух каталогах, чтобы найти ресурс, и, если не находит его ни в одном из них, будет пытаться просто обслужить его из запрошенного местоположения.
RewriteEngine включен
# сначала попытайтесь найти его в каталоге dir1/...
# ...и если нашли, остановитесь и радуйтесь:
RewriteCond "%{DOCUMENT_ROOT}/ dir1 /%{REQUEST_URI}" -f
RewriteRule "^(.+)" "%{DOCUMENT_ROOT}/ dir1 /$1" [L]
# вторая попытка найти его в dir2/...
# ...и если нашли, остановитесь и радуйтесь:
RewriteCond "%{DOCUMENT_ROOT}/ dir2 /%{REQUEST_URI}" -f
RewriteRule "^(.+)" "%{DOCUMENT_ROOT}/ dir2 /$1" [L]
# иначе переходите к другим директивам Alias или ScriptAlias,
# и т. д.
Правило перезаписи "^" "-" [PT]
Перенаправление на географически распределенные серверы
- Описание:
-
У нас есть множество зеркал нашего веб-сайта, и мы хотим перенаправлять людей на то, которое находится в той стране, где они находятся.
- Решение:
-
Глядя на имя хоста запрашивающего клиента, мы определяем, из какой страны он пришел. Если мы не можем выполнить поиск по их IP-адресу, мы возвращаемся к серверу по умолчанию.
Мы будем использовать RewriteMap
директиву для создания списка серверов, которые мы хотим использовать.
Имя хоста
RewriteEngine включен
Мультиплекс RewriteMap "txt:/path/to/map.mirrors"
RewriteCond "%{REMOTE_HOST}" "([az]+)$" [NC]
RewriteRule "^/(.*)$" "${multiplex: %1 |http://www.example.com/}$1" [R,L]
## map.mirrors -- Multiplexing Map
de http://www.example.de/
uk http://www.example.uk/
com http://www.example.com/
##EOF##
- Обсуждение
-
Этот набор правил основан на
HostNameLookups
set on , что может сильно сказаться на производительности.
Директива RewriteCond
фиксирует последнюю часть имени хоста запрашивающего клиента — код страны — и следующее правило RewriteRule использует это значение для поиска соответствующего зеркального хоста в файле сопоставления.
Контент, зависящий от браузера
- Описание:
-
Мы хотим предоставлять различный контент в зависимости от браузера или пользовательского агента, который запрашивает контент.
- Решение:
-
Мы должны решить, основываясь на HTTP-заголовке «User-Agent», какой контент обслуживать. Следующая конфигурация делает следующее: Если HTTP-заголовок «User-Agent» содержит «Mozilla/3», страница foo.html
перезаписывается foo.NS.html и перезапись останавливается. Если используется браузер «Lynx» или «Mozilla» версии 1 или 2, URL-адрес становится foo.20.html . Все остальные браузеры получают страницу foo.32.html . Это делается с помощью следующего набора правил:
RewriteCond "%{HTTP_USER_AGENT}" "^ Mozilla/3 .*"
RewriteRule "^foo\.html$" "foo.NS .html " [ L ]
RewriteCond "%{HTTP_USER_AGENT}" "^Lynx/" [ИЛИ]
RewriteCond "%{HTTP_USER_AGENT}" "^Mozilla/[12]"
RewriteRule "^foo\.html$" "foo. 20 .html" [ L ]
RewriteRule "^foo\.html$" "foo.32 .html " [ L ]
Канонические URL-адреса
- Описание:
-
На некоторых веб-серверах существует более одного URL-адреса для ресурса. Обычно есть канонические URL-адреса (которые фактически используются и распространяются) и те, которые являются просто ярлыками, внутренними и так далее. Независимо от того, какой URL-адрес указал пользователь вместе с запросом, в конечном итоге он должен увидеть канонический URL-адрес в адресной строке своего браузера.
- Решение:
-
Мы делаем внешнее перенаправление HTTP для всех неканонических URL-адресов, чтобы исправить их в представлении местоположения в браузере и для всех последующих запросов. В приведенном ниже примере набора правил мы заменяем /puppies и /canines
на канонический /dogs .
RewriteRule "^/(щенки|собаки)/(.*)" "/dogs/$2" [R]
- Обсуждение:
-
На самом деле это должно быть выполнено с помощью директив Redirect или RedirectMatch:
RedirectMatch "^/(щенки|собаки)/(.*)" "/dogs/$2"
Взолнованный DocumentRoot
- Описание:
-
Обычно адрес DocumentRoot
веб-сервера напрямую связан с URL-адресом " / ". Но часто эти данные не имеют приоритета высшего уровня. Например, вы можете пожелать, чтобы посетители при первом входе на сайт переходили в определенный подкаталог /about/ . Этого можно добиться с помощью следующего набора правил:
- Решение:
-
Мы перенаправляем URL-адрес / на
/about/ :
RewriteEngine включен
RewriteRule "^/$" "/about/" [ R ]
Обратите внимание, что это также может быть обработано с помощью RedirectMatch директивы:
RedirectMatch "^/$" "http://example.com/about/"
Также обратите внимание, что в примере перезаписывается только корневой URL-адрес. То есть переписывает запрос на http://example.com/ , но не запрос на http://example.com/page.html . Если вы действительно изменили корень своего документа, то есть если весь ваш контент фактически находится в этом подкаталоге, гораздо предпочтительнее просто изменить вашу DocumentRoot
директиву или переместить весь контент вверх в один каталог, а не переписывать URL-адреса.
Резервный ресурс
- Описание:
- Вы хотите, чтобы один ресурс (скажем, определенный файл, такой как index.php) обрабатывал все запросы, поступающие в конкретный каталог, за исключением тех, которые должны направляться к существующему ресурсу, такому как изображение или файл css.
- Решение:
-
FallbackResource Начиная с версии 2.2.16 для этого следует использовать директиву:
<Каталог "/var/www/мой_блог">
Резервный ресурс "index.php"
</Каталог>
Однако в более ранних версиях Apache или если ваши потребности более сложны, вы можете использовать вариант следующего набора перезаписи для достижения той же цели:
<Каталог "/var/www/мой_блог">
RewriteBase "/мой_блог"
RewriteCond "/var/www/my_blog/%{REQUEST_FILENAME}" !-f
RewriteCond "/var/www/my_blog/%{REQUEST_FILENAME}" !-d
RewriteRule "^" "index.php" [PT]
</Каталог>
Если, с другой стороны, вы хотите передать запрошенный URI в качестве аргумента строки запроса в index.php, вы можете заменить это RewriteRule на:
RewriteRule "(.*)" "index.php?$1" [PT,QSA]
Обратите внимание, что эти наборы правил можно использовать как в .htaccess
файле, так и в блоке <Directory>.
Переписать строку запроса
- Описание:
- Вы хотите получить конкретное значение из строки запроса и либо заменить его, либо включить в другой компонент URL-адреса.
- Решения:
-
Во многих решениях в этом разделе будет использоваться одно и то же условие, при котором совпадающее значение остается в обратной ссылке %2. %1 — это начало строки запроса (до интересующего ключа), а %3 — остаток. Это условие немного сложно для гибкости и для того, чтобы избежать двойных '&&' в заменах.
- Это решение удаляет соответствующий ключ и значение:
# Удалить mykey=???
RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
Правило перезаписи "(.*)" "$1?%1%3"
- Это решение использует захваченное значение в подстановке URL, отбрасывая остальную часть исходного запроса, добавляя '?':
# Скопировать из строки запроса в PATH_INFO
RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
RewriteRule "(.*)" "$1/products/%2/?" [ПТ]
- Это решение проверяет захваченное значение в последующем условии:
# Зафиксировать значение mykey в строке запроса
RewriteCond "%{QUERY_STRING}" "(.*(?:^|&))mykey=([^&]*)&?(.*)&?$"
RewriteCond "%2" !=не очень секретное значение
Правило перезаписи "(.*)" - [F]
- Это решение показывает обратную сторону предыдущих, копируя компоненты пути (возможно, PATH_INFO) из URL-адреса в строку запроса.
# Нужный URL-адрес может быть /products/kitchen-sink, и скрипт ожидает
# /path?products=kitchen-sink.
RewriteRule "^/?path/([^/]+)/([^/]+)" "/path?$1=$2" [PT]
|
|