Перенаправление, изменение URL-адресов или перенаправление HTTP на HTTPS в Apache — все, что вы хотели знать о правилах mod_rewrite, но боялись спросить

Перенаправление, изменение URL-адресов или перенаправление HTTP на HTTPS в Apache — все, что вы хотели знать о правилах mod_rewrite, но боялись спросить

ЭтоКанонический вопросо mod_rewrite от Apache.

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

  • Изменение HTTP на HTTPS (или наоборот)
  • Изменение запроса на страницу, которая больше не существует, на новую замену.
  • Изменение формата URL (например, ?id=3433 на /id/3433 )
  • Представление другой страницы в зависимости от браузера, в зависимости от реферера, в зависимости от всего, что возможно под луной и солнцем.
  • Все, что вы хотите сделать с URL

Все, что вы хотели знать о правилах Mod_Rewrite, но боялись спросить!

Как мне стать экспертом в написании правил mod_rewrite?

  • Каков основной формат и структура правил mod_rewrite?
  • Какую форму/вид регулярных выражений мне нужно иметь, чтобы иметь четкое представление?
  • Каковы наиболее распространенные ошибки/подводные камни при написании правил переписывания?
  • Какой метод тестирования и проверки правил mod_rewrite является хорошим?
  • Следует ли мне знать о влиянии правил mod_rewrite на SEO или производительность?
  • Бывают ли ситуации, когда mod_rewrite может показаться подходящим инструментом для работы, но на самом деле таковым не является?
  • Каковы некоторые распространенные примеры?

Место для проверки ваших правил

Theтестер htaccessвеб-сайт — отличное место, чтобы поиграться с правилами и протестировать их. Он даже показывает вывод отладки, чтобы вы могли увидеть, что совпало, а что нет.

решение1

порядок синтаксиса mod_rewrite

mod_rewrite имеет некоторые особые правила упорядочивания, которые влияют на обработку. Перед тем, как что-либо будет сделано, RewriteEngine Onнеобходимо задать директиву, поскольку это включает обработку mod_rewrite. Это должно быть до любых других директив перезаписи.

RewriteCondпредшествующее RewriteRuleделает это ОДНО правило подчиненным условию. Любые последующие RewriteRules будут обрабатываться так, как если бы они не подчинялись условию.

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule $/blog/(.*)\.html        $/blog/$1.sf.html

В этом простом случае, если HTTP-реферер находится на serverfault.com, перенаправьте запросы блога на специальные страницы serverfault (мы просто такие особенные). Однако, если бы в приведенном выше блоке была дополнительная строка RewriteRule:

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule $/blog/(.*)\.html        $/blog/$1.sf.html
RewriteRule $/blog/(.*)\.jpg         $/blog/$1.sf.jpg

Все файлы .jpg будут отправляться на специальные страницы serverfault, а не только те, у которых есть реферер, указывающий, что они пришли отсюда. Это явно не является целью написания этих правил. Это можно сделать с помощью нескольких правил RewriteCond:

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.html        /blog/$1.sf.html
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.jpg         /blog/$1.sf.jpg

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

RewriteEngine On
RewriteCond %{HTTP_REFERER}                ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.(html|jpg)        /blog/$1.sf.$2

Более сложный RewriteRule содержит условия для обработки. Последняя скобка (html|jpg)сообщает RewriteRule, что нужно сопоставить либо , htmlлибо jpg, и представить совпавшую строку как $2 в перезаписанной строке. Это логически идентично предыдущему блоку с двумя парами RewriteCond/RewriteRule, просто это делается на двух строках вместо четырех.

Несколько строк RewriteCond неявно объединены с помощью AND и могут быть явно объединены с помощью OR. Для обработки рефереров как от ServerFault, так и от Super User (явное OR):

RewriteEngine On
RewriteCond %{HTTP_REFERER}                ^https?://serverfault\.com(/|$)    [OR]
RewriteCond %{HTTP_REFERER}                ^https?://superuser\.com(/|$)
RewriteRule ^/blog/(.*)\.(html|jpg)        /blog/$1.sf.$2

Для обслуживания страниц, на которые ссылается ServerFault, с помощью браузеров Chrome (неявное И):

RewriteEngine On
RewriteCond %{HTTP_REFERER}                ^https?://serverfault\.com(/|$)
RewriteCond %{HTTP_USER_AGENT}             ^Mozilla.*Chrome.*$
RewriteRule ^/blog/(.*)\.(html|jpg)        /blog/$1.sf.$2

RewriteBaseтакже зависит от порядка, поскольку определяет, как следующие RewriteRuleдирективы обрабатывают свою обработку. Это очень полезно в файлах .htaccess. Если используется, это должна быть первая директива под "RewriteEngine on" в файле .htaccess. Рассмотрим этот пример:

RewriteEngine On
RewriteBase /blog
RewriteCond %{HTTP_REFERER}           ^https?://serverfault\.com(/|$)
RewriteRule ^(.*)\.(html|jpg)         $1.sf.$2

Это сообщает mod_rewrite, что данный конкретный URL, который он в данный момент обрабатывает, был получен посредствомhttp://example.com/blog/вместо физического пути к каталогу (/home/$Username/public_html/blog) и обрабатывать его соответствующим образом. Из-за этого он RewriteRuleсчитает, что его начало строки находится после "/blog" в URL. Вот одно и то же, записанное двумя разными способами. Один с RewriteBase, другой без:

RewriteEngine On

##Example 1: No RewriteBase##
RewriteCond %{HTTP_REFERER}                                   ^https?://serverfault\.com(/|$)
RewriteRule /home/assdr/public_html/blog/(.*)\.(html|jpg)     $1.sf.$2

##Example 2: With RewriteBase##
RewriteBase /blog
RewriteCond %{HTTP_REFERER}           ^https?://serverfault\.com(/|$)
RewriteRule ^(.*)\.(html|jpg)         $1.sf.$2

Как вы можете видеть, RewriteBaseпозволяет переписывать правила, чтобы использовать веб-сайтпуть к контенту, а не к веб-сервер, что может сделать их более понятными для тех, кто редактирует такие файлы. Также они могут сделать директивы короче, что имеет эстетическую привлекательность.


Синтаксис соответствия RewriteRule

Само RewriteRule имеет сложный синтаксис для сопоставления строк. Я расскажу о флагах (таких как [PT]) в другом разделе. Поскольку системные администраторы учатся на примерах чаще, чем читаяman-страницаЯ приведу примеры и объясню, что они делают.

RewriteRule ^/blog/(.*)$    /newblog/$1

Конструкция .*соответствует любому одиночному символу ( .) ноль или более раз ( *). Заключение его в скобки указывает ему предоставить строку, которая была сопоставлена, как переменную $1.

RewriteRule ^/blog/.*/(.*)$  /newblog/$1

В этом случае первый .* НЕ был заключен в скобки, поэтому не предоставлен в переписанной строке. Это правило удаляет уровень каталога на новом сайте-блоге. (/blog/2009/sample.html становится /newblog/sample.html).

RewriteRule ^/blog/(2008|2009)/(.*)$   /newblog/$2

В этом случае первое выражение в скобках устанавливает группу соответствия. Это становится $1, который не нужен и, следовательно, не используется в переписанной строке.

RewriteRule ^/blog/(2008|2009)/(.*)$   /newblog/$1/$2

В этом случае мы используем $1 в переписанной строке.

RewriteRule ^/blog/(20[0-9][0-9])/(.*)$   /newblog/$1/$2

Это правило использует специальный синтаксис скобок, который определяет символдиапазон. [0-9] соответствует цифрам от 0 до 9. Это конкретное правило будет обрабатывать годы с 2000 по 2099.

RewriteRule ^/blog/(20[0-9]{2})/(.*)$  /newblog/$1/$2

Это правило выполняет то же самое, что и предыдущее, но часть {2} указывает, что предыдущий символ (в данном случае — квадратное выражение) должен совпадать с ним два раза.

RewriteRule ^/blog/([0-9]{4})/([a-z]*)\.html   /newblog/$1/$2.shtml

Этот случай будет соответствовать любой строчной букве во втором выражении соответствия, и сделает это для максимально возможного количества символов. Конструкция \.сообщает ему, что точку следует рассматривать как реальную точку, а не как специальный символ, которым она является в предыдущих примерах. Однако она сломается, если в имени файла есть дефисы.

RewriteRule ^/blog/([0-9]{4})/([-a-z]*)\.html  /newblog/$1/$2.shtml

Это перехватывает имена файлов с дефисами. Однако, как -и специальный символ в квадратных скобках, он должен бытьпервыйхарактер в выражении.

RewriteRule ^/blog/([0-9]{4})/([-0-9a-zA-Z]*)\.html   /newblog/$1/$2.shtml

Эта версия перехватывает любое имя файла с буквами, цифрами или -символом в имени файла. Это то, как вы указываете несколько наборов символов в выражении в скобках.


Флаги RewriteRule

Флаги правил перезаписи имеют множество специальных значений и вариантов использования..

RewriteRule ^/blog/([0-9]{4})/([-a-z]*).\html  /newblog/$1/$2.shtml  [L]

Флаг находится [L]в конце приведенного выше выражения. Можно использовать несколько флагов, разделенных запятой. Связанная документация описывает каждый из них, но вот они в любом случае:

Л= Последний. Прекратите обработку RewriteRules, как только этот совпадет. Порядок имеет значение!
С= Цепочка. Продолжить обработку следующего RewriteRule. Если это правило не совпадает, то следующее правило не будет выполнено. Подробнее об этом позже.
Э= Установить переменную окружения. Apache имеет различные переменные окружения, которые могут влиять на поведение веб-сервера.
Ф= Запрещено. Возвращает ошибку 403-Forbidden, если это правило соответствует.
г= Ушел. Возвращает ошибку 410-Ушел, если это правило соответствует.
ЧАС= Обработчик. Заставляет обрабатывать запрос так, как если бы он имел указанный MIME-тип.
Н= Далее. Заставляет правило начинаться снова и повторно сопоставляться. БУДЬТЕ ОСТОРОЖНЫ! Могут возникнуть циклы.
NC= Без учета регистра. Позволяет jpgсопоставлять как jpg, так и JPG.
СВ= Без экранирования. Предотвращает перезапись специальных символов (. ? # и т. д.) в их шестнадцатеричные эквиваленты.
НС= Никаких подзапросов. Если вы используете включения на стороне сервера, это предотвратит совпадения с включенными файлами.
п= Proxy. Заставляет правило обрабатываться mod_proxy. Прозрачно предоставлять контент с других серверов, поскольку ваш веб-сервер извлекает его и повторно обслуживает. Это опасный флаг, так как плохо написанный превратит ваш веб-сервер в открытый прокси, а это плохо.
ПТ= Pass Through. Учитывать операторы Alias ​​при сопоставлении RewriteRule.
QSA= QSAppend. Когда исходная строка содержит запрос (http://example.com/thing?asp=foo) добавить исходную строку запроса к переписанной строке. Обычно она отбрасывается. Важно для динамического контента.
р= Перенаправление. Обеспечивает HTTP-перенаправление на указанный URL. Может также предоставлять точный код перенаправления [R=303]. Очень похоже на RedirectMatch, который быстрее и должен использоваться, когда это возможно.
С= Пропустить. Пропустить это правило.
Т= Тип. Укажите mime-тип возвращаемого содержимого. Очень похоже на AddTypeдирективу.

Помните, как я сказал, что это RewriteCondотносится к одному и только одному правилу? Ну, вы можете обойти это с помощью цепочки.

RewriteEngine On
RewriteCond %{HTTP_REFERER}          ^https?://serverfault\.com(/|$)
RewriteRule ^/blog/(.*)\.html        /blog/$1.sf.html     [C]
RewriteRule ^/blog/(.*)\.jpg         /blog/$1.sf.jpg

Поскольку первое RewriteRule имеет флаг Chain, второе rewrite-rule будет выполнено, когда выполнится первое, то есть когда сработает предыдущее правило RewriteCond. Удобно, если регулярные выражения Apache заставляют вас ломать голову. Однако метод all-in-one-line, на который я указываю в первом разделе, быстрее с точки зрения оптимизации.

RewriteRule ^/blog/([0-9]{4})/([-0-9a-zA-Z]*)\.html   /newblog/$1/$2.shtml

Это можно упростить с помощью флагов:

RewriteRule ^/blog/([0-9]{4})/([-0-9a-z]*)\.html   /newblog/$1/$2.shtml   [NC]

Кроме того, некоторые флаги также применяются к RewriteCond. В частности, NoCase.

RewriteCond %{HTTP_REFERER}        ^https?://serverfault\.com(/|$)     [NC]

Будет соответствовать "ServerFault.com"

решение2

Каков основной формат и структура правил mod_rewrite?

Я полагаюсь на превосходный ответ sysadmin1138 по этим вопросам.

Какую форму/вид регулярных выражений мне нужно иметь, чтобы иметь четкое представление?

В дополнение к порядку синтаксиса, сопоставлению синтаксиса/регулярным выражениям и флагам RewriteRule, описанным sysadmin1138, я считаю, что стоит упомянуть, что mod_rewrite предоставляет переменные среды Apache на основе заголовков HTTP-запросов и конфигурации Apache.

Я бы посоветовалУчебное пособие по отладке mod_rewrite от AskApacheдля получения полного списка переменных, которые могут быть доступны для mod_rewrite.

Каковы наиболее распространенные ошибки/подводные камни при написании правил переписывания?

Большинство проблем с RewriteRule возникают из-за неправильного понимания синтаксиса PCRE/неправильного экранирования специальных символов или отсутствия понимания содержимого переменных, используемых для сопоставления.

Типичные проблемы и рекомендуемые методы устранения:

  • 500 - внутренняя ошибка сервера-Удалить элементы управления кареткой Windowsв конфигурационном файле(ах), если он присутствует, убедитесь, что mod_rewrite включен (оберните директивы вIfModule(условно, чтобы избежать этого сценария), проверьте синтаксис директив, закомментируйте директивы, пока проблема не будет выявлена)
  • Перенаправление цикла- Используйте RewriteLog и RewriteLogLevel, комментируйте директивы, пока проблема не будет выявлена.

Какой метод тестирования и проверки правил mod_rewrite является хорошим?

Сначала посмотрите на содержимое переменных среды, с которыми вы планируете проводить сопоставление. Если у вас установлен PHP, это так же просто, как добавить следующий блок в ваше приложение:

<?php
  var_dump($_SERVER);
?>

... затем напишите свои правила (предпочтительно для тестирования на сервере разработки) и отметьте любые несоответствия или действия в вашем ApacheЖурнал ошибокфайл.

Для более сложных правил используйте mod_rewriteRewriteLogдиректива для записи активности в файл и установкиRewriteLogLevel 3

Следует ли мне знать о влиянии правил mod_rewrite на SEO или производительность?

AllowOverride allвлияет на производительность сервера, поскольку Apache должен проверять наличие .htaccessфайлов и анализировать директивы при каждом запросе. Если возможно, сохраните все директивы в конфигурации VirtualHost для вашего сайта или включите .htaccessпереопределения только для тех каталогов, которым они нужны.

Google'sРуководство для веб-мастеровчетко заявите: «Не обманывайте своих пользователей и не предоставляйте поисковым системам контент, отличный от того, который вы показываете пользователям. Это обычно называется «маскировкой». - избегайте создания директив mod_rewrite, которые фильтруют контент для роботов поисковых систем.

Поисковые роботы предпочитают сопоставление контента:URI 1:1 (это основа для ранжирования ссылок на контент) — если вы используете mod_rewrite для создания временных перенаправлений или обслуживаете один и тот же контент под несколькими URI, рассмотрите возможность указанияканонический URIв ваших HTML-документах.

Бывают ли ситуации, когда mod_rewrite может показаться подходящим инструментом для работы, но на самом деле таковым не является?

Это огромная (и потенциально спорная) тема сама по себе — лучше (на мой взгляд) рассматривать каждый случай индивидуально и позволить спрашивающим самостоятельно определять, соответствуют ли предлагаемые решения их потребностям.

Каковы некоторые распространенные примеры?

Советы и хитрости по mod_rewrite от AskApacheохватывает практически все распространенные варианты использования, которые регулярно возникают, однако «правильное» решение для конкретного пользователя может зависеть от сложности конфигурации пользователя и существующих директив (вот почему обычно полезно посмотреть, какиедругойдирективы, которые пользователь использует при возникновении вопроса mod_rewrite).

решение3

Как и многие администраторы/разработчики, я годами боролся со сложностями правил переписывания и недоволен существующей документацией Apache, поэтому я решил в качестве личного проекта разобраться в том, как mod_rewriteна самом деле работает и взаимодействует с остальной частью ядра Apache. Поэтому в течение последних нескольких месяцев я занимался инструментированием тестовых случаев и straceуглублялся в исходный код, чтобы разобраться со всем этим.

Вот несколько ключевых замечаний, которые необходимо учитывать разработчикам правил переписывания:

  • Некоторые аспекты перезаписи являются общими для конфигурации сервера, виртуального хоста, каталога, обработки .htaccess.однако
  • Некоторые процессы обработки корневой конфигурации (конфигурация сервера, виртуальный хост и каталог) существенно отличаются от .htaccessпроцессов обработки PerDir ( ).
  • Хуже того, обработка PerDir может практически без разбора запускать цикл ВНУТРЕННЕГО ПЕРЕНАПРАВЛЕНИЯ, корневые элементы конфигурации должны быть написаны с учетом того, что такая обработка PerDir может это запускать.

Я бы даже сказал, что по этой причине вам придется разделить сообщества пользователей, занимающихся переписыванием, на две категории и рассматривать их как совершенно отдельные:

  • Те, у кого есть root-доступ к конфигурации Apache. Обычно это администратор/разработчик с выделенным сервером/виртуальной машиной для приложения, и сообщение здесь довольно простое: избегайте использования .htaccessфайлов, если это вообще возможно; делайте все в конфигурации сервера или vhost. Отладка достаточно проста, поскольку разработчик может настроить отладку и имеет доступ к файлам rewrite.log.

  • Пользователи службы общего хостинга (SHS).

    • Такие пользователииметьиспользовать .htaccessобработку Perdir, поскольку альтернативы нет.
    • Хуже того, уровень навыков таких пользователей (в плане использования логики mod_rewrite, основанной на регулярных выражениях) обычно значительно ниже, чем у опытных администраторов.
    • Apache и хостинг-провайдеры не предлагают отладочной/диагностической поддержки. Единственная диагностическая информация — это успешное перенаправление, перенаправление на неправильный URI или код статуса 404/500. Это оставляет их в замешательстве и беспомощности.
    • Apache крайне слабо объясняет, как работает переписывание для этого варианта использования. Например, он не дает четкого объяснения, какой .htaccessфайл PerDir выбран и почему. Он не объясняет тонкости цикличности PerDir и как этого избежать.

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

Я написал несколько постов в блоге в стиле статей (например,Подробнее об использовании правил перезаписи в файлах .htaccess), который охватывает множество подробных моментов, которые я не буду повторять здесь, чтобы сделать этот пост коротким. У меня есть свой собственный общий сервис, а также поддержка некоторых специализированных и VM FLOSS проектов. Я начал использовать стандартную LAMP VM в качестве тестового средства для моей учетной записи SHS, но в конце концов я обнаружил, что лучше сделать надлежащую зеркальную VM (описаннуюздесь).

Однако с точки зрения того, как сообщество администраторов должно поддерживать .htaccessпользователей, я считаю, что нам необходимо разработать и предложить:

  • Последовательное описание того, как на самом деле работает система перезаписи при обработке PerDir
  • Набор рекомендаций/рекомендаций по написанию .htaccessправил переписывания
  • Простой веб-анализатор скриптов перезаписи, похожий на анализаторы HTML W3C, но с помощью которого пользователи могут вводить тестовые URI или тестовые векторы того же самого и получать немедленный журнал логического потока перезаписи.
  • Советы по получению встроенной диагностики из ваших правил (например,

    • Используйте [E=VAR:EXPR]тот факт, что EXPRобратные ссылки ($N или %N) будут расширены, чтобы сделать их доступными в качестве диагностики для целевого скрипта.
    • Если вы тематически упорядочиваете правила перезаписи, используя флаги [OR],[C],[SKIP] и [L], чтобы вся схема перезаписи работалабезнеобходимо использовать внутреннее перенаправление, то вы можете добавить следующее в качестве правила 1, чтобы избежать всех проблем с зацикливанием:

      RewriteCond %{ENV:REDIRECT_STATUS} !=""
      RewriteRule .  -  [L]
      

решение4

Каковы наиболее распространенные ошибки/подводные камни при написании правил переписывания?

Действительно простая ловушка — это когда вы переписываете URL-адреса, которые изменяют видимый путь, например, с /base/1234/index.htmlна /base/script.php?id=1234. Любые изображения или CSS с относительными путями к местоположению скрипта не будут найдены клиентом. Ряд вариантов решения этой проблемы можно найти наэтот часто задаваемый вопрос.

Связанный контент