Советы по отладке.htaccess переписать правила

У многих авторов возникают проблемы с отладкой операторов RewriteRule и RewriteCond в их .htaccessфайлы. Большинство из них используют службу общего хостинга и поэтому не имеют доступа к конфигурации корневого сервера. Они не могут избежать использования.htaccessфайлы для перезаписи ине могут включить RewriteLogLevel", как предлагают многие респонденты. Также есть много .htaccessКонкретные подводные камни и ограничения не очень хорошо освещены. Настройка локального тестового стека LAMP включает в себя слишком много кривой обучения для большинства.

Итак, мой вопрос здесь заключается в том, как бы мы порекомендовали им отладить свои правиласамостоятельно. Я приведу несколько предложений ниже. Другие предложения будут оценены.

  1. Поймите, что механизм mod_rewrite циклически проходит.htaccessфайлы Двигатель запускает этот цикл:

    do
      execute server and vhost rewrites (in the Apache Virtual Host Config)
      find the lowest "Per Dir" .htaccess file on the file path with rewrites enabled
      if found(.htaccess)
         execute .htaccess rewrites (in the user's directory)
    while rewrite occurred
    

    Таким образом, ваши правила будут выполняться неоднократно, и если вы измените путь URI, то это может привести к выполнению других .htaccessфайлы, если они существуют. Поэтому убедитесь, что вы завершаете этот цикл, если необходимо, добавив дополнительные RewriteCond прекратить правила стрельбы. Также удалите любой более низкий уровень .htaccess переписывать наборы правил, если явно не намерены использовать многоуровневые наборы правил.

  2. Убедитесь, что синтаксис каждого регулярного выражения правильный, протестировав набор тестовых шаблонов, чтобы убедиться, что он является допустимым синтаксисом и выполняет то, что вы собираетесь с полным диапазоном тестовых URI. Смотрите ответ ниже для более подробной информации.

  3. Построить свои правила постепенно в тестовом каталоге. Вы можете использовать "выполнить самые глубокие .htaccess функция "файл на пути" для установки отдельного тестового каталога (дерева) и отладки наборов правил здесь, не нарушая ваши основные правила и не останавливая работу вашего сайта. Вы должны добавлять их по одному, потому что это единственный способ локализовать сбои по индивидуальным правилам.

  4. Используйте фиктивную заглушку скрипта для вывода переменных сервера и окружения. (См. Листинг 2). Если ваше приложение использует, скажем, blog/index.php тогда вы можете скопировать это в test/blog/index.php и использовать его, чтобы проверить свои правила блога в test подкаталог. Вы также можете использовать переменные окружения, чтобы убедиться, что механизм перезаписи правильно интерпретирует строки подстановки, например

    RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html]
    

    и найдите эти переменные REDIRECT_* в дампе phpinfo. Кстати, я использовал это и обнаружил на моем сайте, что я должен был использовать %{ENV:DOCUMENT_ROOT_REAL} вместо. В случае зацикливания редиректора переменные REDIRECT_REDIRECT_* перечисляют предыдущий проход. Так далее..

  5. Убедитесь, что ваш браузер не укушен неправильным кэшированием 301 перенаправлений. Смотрите ответ ниже. Спасибо Ulrich Palha за это.

  6. Механизм перезаписи кажется чувствительным к каскадным правилам внутри .htaccess контекст, (вот где RewriteRule приводит к подстановке, и это относится к дальнейшим правилам), поскольку я обнаружил ошибки с внутренними подзапросами (1) и неправильной обработкой PATH_INFO, которую часто можно предотвратить с помощью [NS], [L] и [PT] флаги.

Есть еще комментарии или предложения?

Листинг 1 - phpinfo

<?php phpinfo(INFO_ENVIRONMENT|INFO_VARIABLES);

19 ответов

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

1. Используйте фальшивый пользовательский агент

При тестировании нового правила добавьте условие, чтобы оно выполнялось только с fake пользовательский агент, который вы будете использовать для ваших запросов. Таким образом, это не повлияет ни на кого на вашем сайте.

например

#protect with a fake user agent
RewriteCond %{HTTP_USER_AGENT}  ^my-fake-user-agent$
#Here is the actual rule I am testing
RewriteCond %{HTTP_HOST} !^www\.domain\.com$ [NC] 
RewriteRule ^ http://www.domain.com%{REQUEST_URI} [L,R=302] 

Если вы используете Firefox, вы можете использовать User Agent Switcher для создания поддельной строки агента пользователя и проверки.

2. Не используйте 301, пока не закончите тестирование

Я видел так много постов, где люди все еще проверяют свои правила и используют 301. НЕ

Если вы не используете предложение 1 на своем сайте, 301 повлияет не только на вас, но и на любого посетителя вашего сайта.

Помните, что они являются постоянными и агрессивно кешируются вашим браузером. Вместо этого используйте 302, пока не будете уверены, затем измените его на 301.

3. Помните, что 301 агрессивно кэшируются в вашем браузере

Если ваше правило не работает и выглядит правильно для вас, а вы не использовали предложения 1 и 2, проведите повторную проверку после очистки кэша браузера или в режиме приватного просмотра.

4. Используйте инструмент HTTP Capture

Используйте инструмент захвата HTTP, такой как Fiddler, чтобы увидеть фактический трафик HTTP между вашим браузером и сервером.

В то время как другие могут сказать, что ваш site does not look rightвместо этого вы можете увидеть и сообщить, что all of the images, css and js are returning 404 errorsБыстро сужает проблему.

В то время как другие сообщат, что вы started at URL A and ended at URL C, вы сможете увидеть, что они начали в URL A, were 302 redirected to URL B and 301 redirected to URL C, Даже если URL C был конечной целью, вы будете знать, что это плохо для SEO и должно быть исправлено.

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


Онлайн тестирование перезаписи.htaccess

Я нашел эту справку Googling for RegEx, она избавила меня от необходимости загружать новые .htaccess файлы каждый раз, когда я делаю небольшую модификацию.

с сайта:

тестер htaccess

Чтобы проверить свои правила перезаписи htaccess, просто введите URL-адрес, к которому вы применяете правила, поместите содержимое вашего htaccess в большую область ввода и нажмите кнопку "Проверить сейчас".

Не забывайте, что в файлах.htaccess это относительный URL, который соответствует.

В файле.htaccess следующий RewriteRule никогда не будет совпадать:

RewriteRule ^/(.*)     /something/$s

Установите переменные окружения и используйте заголовки для их получения:

Вы можете создавать новые переменные окружения с помощью строк RewriteRule, как указано в OP:

RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html]

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

Header set TEST_FOOBAR "%{REDIRECT_TEST0}e"

Значение принимает спецификаторы формата, включая %{NAME}e спецификатор для переменных среды (не забывайте строчную букву e). Иногда вам нужно добавить REDIRECT_ префикс, но я не работал, когда префикс добавляется, а когда нет.

Убедитесь, что синтаксис каждого регулярного выражения правильный

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

См. RegexpCheck.php ниже для простого сценария, который вы можете добавить в личный / тестовый каталог на вашем сайте, чтобы помочь вам сделать это. Я сохранил это краткое, а не красивое. Просто мимо этого в файл regexpCheck.php в тестовом каталоге, чтобы использовать его на своем сайте. Это поможет вам составить любое регулярное выражение и проверить его на соответствие списку тестовых случаев. Я использую движок PHP PCRE здесь, но, посмотрев на исходник Apache, он в основном идентичен тому, который используется в Apache. Существует множество практических руководств и учебных пособий, которые предоставляют шаблоны и могут помочь вам развить свои навыки регулярного выражения.

Листинг 1 - regexpCheck.php

<html><head><title>Regexp checker</title></head><body>
<?php 
    $a_pattern= isset($_POST['pattern']) ? $_POST['pattern'] : "";
    $a_ntests = isset($_POST['ntests']) ? $_POST['ntests'] : 1;
    $a_test   = isset($_POST['test']) ? $_POST['test'] : array();

    $res = array(); $maxM=-1; 
    foreach($a_test as $t ){
        $rtn = @preg_match('#'.$a_pattern.'#',$t,$m);
        if($rtn == 1){
            $maxM=max($maxM,count($m));
            $res[]=array_merge( array('matched'),  $m );
        } else {
            $res[]=array(($rtn === FALSE ? 'invalid' : 'non-matched'));
        }
    } 
?> <p>&nbsp; </p>
<form method="post" action="<?php echo $_SERVER['SCRIPT_NAME'];?>">
    <label for="pl">Regexp Pattern: </label>
    <input id="p" name="pattern" size="50" value="<?php echo htmlentities($a_pattern,ENT_QUOTES,"UTF-8");;?>" />
    <label for="n">&nbsp; &nbsp; Number of test vectors: </label>
    <input id="n" name="ntests"  size="3" value="<?php echo $a_ntests;?>"/>
    <input type="submit" name="go" value="OK"/><hr/><p>&nbsp;</p>
    <table><thead><tr><td><b>Test Vector</b></td><td>&nbsp; &nbsp; <b>Result</b></td>
<?php 
    for ( $i=0; $i<$maxM; $i++ ) echo "<td>&nbsp; &nbsp; <b>\$$i</b></td>";
    echo "</tr><tbody>\n";
    for( $i=0; $i<$a_ntests; $i++ ){
        echo '<tr><td>&nbsp;<input name="test[]" value="', 
            htmlentities($a_test[$i], ENT_QUOTES,"UTF-8"),'" /></td>';
        foreach ($res[$i] as $v) { echo '<td>&nbsp; &nbsp; ',htmlentities($v, ENT_QUOTES,"UTF-8"),'&nbsp; &nbsp; </td>';}
        echo "</tr>\n";
    }
?> </table></form></body></html>

Один из пары часов, которые я потратил впустую:

Если вы применили все эти советы и допустили только 500 ошибок, потому что у вас нет доступа к журналу ошибок сервера, возможно, проблема не в.htaccess, а в файлах, на которые он перенаправляет.

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

Убедитесь, что вы используете знак процента перед переменными, а не знак доллара.

Это %{HTTP_HOST}не ${HTTP_HOST}, В файле error_log ничего не будет, не будет внутренних ошибок сервера, ваше регулярное выражение все еще верно, правило просто не будет соответствовать. Это действительно отвратительно, если вы много работаете с шаблонами django / genshi и имеете ${} для переменного замещения в мышечной памяти.

Если вы создаете перенаправления, протестируйте их с помощью curl, чтобы избежать проблем с кэшированием в браузере. Используйте -I для получения только заголовков http. Используйте -L, чтобы следовать всем перенаправлениям.

Что касается 4., вам все равно нужно убедиться, что ваша "заглушка сценария" действительно является целевым URL-адресом после того, как все переписывание выполнено, иначе вы ничего не увидите!

Подобный / связанный трюк (см. Этот вопрос) заключается во вставке временного правила, такого как:

RewriteRule (.*) /show.php?url=$1 [END]

куда show.php это очень простой скрипт, который просто отображает его $_GET параметры (вы также можете отображать переменные окружения, если хотите).

Это остановит переписывание в том месте, где вы вставляете его в набор правил, как точка останова в отладчике.

Если вы используете Apache <2.3.9, вам нужно использовать [L] скорее, чем [END]и вам может понадобиться добавить:

RewriteRule ^show.php$ - [L]

В самом верху вашего набора правил, если URL /show.php само переписывается.

Некоторые ошибки, которые я наблюдал, случаются при написании .htaccess

Использование ^(.*)$ в нескольких правилах, используя ^(.*)$ В большинстве случаев другие правила оказываются бессильными, потому что они соответствуют всем URL-адресам за один удар.

Итак, если мы используем правило для этого URL sapmle/url это также будет потреблять этот URL sapmle/url/string,


[L] Флаг должен использоваться, чтобы убедиться, что наше правило завершило обработку.


Должен знать о:

Разница в% n и $ n

%n подбирается во время %{RewriteCond} часть и $n это спички на %{RewriteRule} часть.

Работа RewriteBase

Директива RewriteBase указывает префикс URL, который будет использоваться для директив RewriteRule для каждого каталога (htaccess), которые заменяют относительный путь.

Эта директива необходима, когда вы используете относительный путь в подстановке в контексте для каталога (htaccess), если не выполняется одно из следующих условий:

Исходный запрос и подстановка находятся под DocumentRoot (в отличие от достижимого другими средствами, такими как Alias). Путь файловой системы к каталогу, содержащему RewriteRule, с суффиксом относительной подстановки, также действителен как URL-путь на сервере (это редко). В Apache HTTP Server 2.4.16 и более поздних версиях эта директива может быть опущена, когда запрос отображается через Alias ​​или mod_userdir.

Если вы работаете не в стандартной среде общего хостинга, а в той, к которой у вас есть доступ администратора (возможно, в вашей локальной тестовой среде), убедитесь, что использование и включены. Они отключены в установке Apache по умолчанию. И в этом случае никакое действие, настроенное в вашем файле, не работает, даже если регулярные выражения совершенно корректны.

Чтобы разрешить использование .htaccess:

Найти файл apache2.conf, в Debian/Ubuntu это в /etc/apache2, а внутри файла раздел

      <Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

и изменить строку AllowOverride Noneк AllowOverride All.

Чтобы включить модуль mod_rewrite:

В Debian/Ubuntu выполните

      sudo a2enmod rewrite

Кстати, чтобы отключить модуль, вы должны использовать a2dismodeвместо a2enmode.

После внесения вышеуказанных изменений в конфигурацию перезапустите Apache, чтобы они вступили в силу:

      sudo systemctl restart apache2

Я нашел этот вопрос, пытаясь отладить проблемы с mod_rewrite, и у него определенно есть несколько полезных советов. Но, в конце концов, самое важное - убедиться, что у вас правильный синтаксис регулярных выражений. Из-за проблем с моим собственным синтаксисом RE установка сценария regexpCheck.php не была приемлемой опцией.

Но поскольку Apache использует Perl-совместимые регулярные выражения (PCRE), любой инструмент, который помогает в написании PCRE, должен помочь. В прошлом я использовал инструмент RegexPlanet с RE Java и Javascript, и был счастлив обнаружить, что они также поддерживают Perl.

Просто введите свое регулярное выражение и один или несколько примеров URL-адресов, и он сообщит вам, соответствует ли регулярное выражение ("1" в столбце "~=") и, если применимо, любым подходящим группам (числа в "split"). столбец будет соответствовать числам, ожидаемым Apache, например, $1, $2 и т. д.) для каждого URL. Они утверждают, что поддержка PCRE находится "в бета-версии", но это было именно то, что мне было нужно для решения моих проблем с синтаксисом.

http://www.regexplanet.com/advanced/perl/index.html

Я бы просто добавил комментарий к существующему ответу, но моя репутация еще не достигла такого уровня. Надеюсь, это кому-нибудь поможет.

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

Я потратил несколько дней на настройку нескольких правил без обратной связи с журналами, только чтобы окончательно отказаться от одного.
Я установил Apache на свой компьютер, скопировал весь сайт на жесткий диск, и весь набор правил был отсортирован по журналам очень быстро.
Затем я пересмотрел свои старые правила, которые работали, и увидел, что они на самом деле не делают то, что хотели. Бомба замедленного действия для немного другого адреса.

В правилах переписывания столько ошибок, что это не совсем логичная вещь.
Вы можете запустить и запустить Apache за десять минут, его 10 МБ, хорошая лицензия, *NIX/WIN/MAC готовы, даже без установки.
Также проверьте строки заголовка вашего сервера и получите ту же версию Apache из архива, если она старая. Мой OP по-прежнему на 2.0, многие вещи не поддерживаются.

Лучший способ отладить его!

Добавлять LogLevel notice rewrite:trace8в Apache, чтобы регистрировать все уведомления о mod_rewrite. Если вы находитесь на виртуальном хостинге и не имеете доступа к httpd.confзатем протестируйте его локально и загрузите на работающий сайт. После включения это создает очень большой журнал за очень короткое время, это означает, что его все равно нельзя протестировать на реальном сервере.

Я оставлю это здесь, возможно, очевидную деталь, но заставляю меня биться в течение нескольких часов: будьте осторожны, используя %{REQUEST_URI} потому что то, что @Krist van Besien говорит в своем ответе, совершенно верно, но не для строки REQUEST_URI, потому что выход этой TestString начинается с /, Так что будьте аккуратнее:

RewriteCond %{REQUEST_URI} ^/assets/$  
                            ^
                            | check this pesky fella right here if missing

Возможно, лучший способ отладки правил перезаписи — вообще не использовать правила перезаписи, а перенести обработку URL-адресов из файла htaccess в файл PHP (назовем его router.php). Затем вы можете использовать PHP для выполнения любых манипуляций, которые вам нравятся, с надлежащим обнаружением ошибок и обычными способами отладки. Это даже работает быстрее, поскольку вам не нужно использовать модуль перезаписи.

Чтобы сразу передать управление из .htaccess в router.php для любого URL, не найденного в файловой системе, достаточно прописать в .htaccess следующую строчку:

      FallbackResource router.php

Да, это действительно так просто. И да, это действительно работает. Попробуйте.

Примечание. Вам может понадобиться директива ErrorDocument в вашем файле .htacess для явной передачи управления определенными URL-адресами в ваш файл router.php при статусе HTTP 404, особенно если вы наследуете от родительского файла htaccess, который обрабатывает статус 404. Таким образом, это сделает его всего две строки для передачи управления файлу маршрутизатора.

(Похоже на идею Doin) Чтобы показать, что сопоставляется, я использую этот код

$keys = array_keys($_GET);
foreach($keys as $i=>$key){
    echo "$i => $key <br>";
}

Сохраните его в r.php в корневом каталоге сервера, а затем выполните несколько тестов в.htaccess.
Например, я хочу сопоставить URL-адреса, которые не начинаются с языкового префикса

RewriteRule ^(?!(en|de)/)(.*)$ /r.php?$1&$2 [L] #$1&$2&...
RewriteRule ^(.*)$ /r.php?nomatch [L] #report nomatch and exit

Как указывает @JCastell, онлайн-тестер хорошо тестирует отдельные перенаправления для файла.htaccess. Однако более интересным является предоставленный API, который можно использовать для пакетного тестирования списка URL-адресов с использованием объекта json. Однако, чтобы сделать его более полезным, я написал небольшой файл сценария bash, который использует curl и jq для отправки списка URL-адресов и синтаксического анализа ответа json в форматированный вывод CSV с номером строки и правилом, сопоставленным в файле htaccess. вместе с перенаправленным URL-адресом, что делает его очень удобным для сравнения списка URL-адресов в электронной таблице и быстрого определения, какие правила не работают.

Если вы работаете с URL-адресом, вы можете проверить, включен ли параметр "Включить перезапись модов".

Другие вопросы по тегам