Почему этот флаг [L] не может предотвратить применение следующего правила перезаписи?
Я думал, что флаг " L " должен был предотвратить применение последующих правил. Однако в этом примере:
RewriteRule foo bar [L]
RewriteRule bar qux
Я получаю http://mysite/foo
переписанный как http://mysite/qux
. Я ожидал http://mysite/bar
. Чего мне здесь не хватает?
2 ответа:
Поведение флага
[L]
довольно плохо описано в документах Apache. Чтобы понять, как это работает, нам сначала нужно знать, как Apache обрабатывает RewriteRules. Возьмем простой примерRewriteRule ^something /somethingelse #1 RewriteRule ^somewhere /somewhereelse #2 RewriteRule ^someplace /anotherplace #3
В этой ситуации с несколькими правилами и без флагов
[L]
, если мы запросим/something
, Apache перепишет это/somethingelse
(согласно #1), затем попробуйте правила #2 и #3. После того, как все правила обработаны, он проверяет, совпадает ли URL, вышедший из RewriteRules, с URL, который заниматься. Если это не так, Apache снова начинает обрабатывать все правила, пока input= = = output (или максимальное число перенаправлений не будет выполнено, чтобы предотвратить бесконечные циклы).Теперь, если мы изменим Правило #1 и добавим к нему
[L]
, и мы снова запросим/something
, Apache перепишет его в/somethingelse
(согласно #1), а затем прекратит обработку правил, т. е. он не будет обрабатывать #2 и #3. Но затем, поскольку URL-адрес, который вышел, не совпадает с URL-адресом, который вошел (это суть здесь), обработка перезапускает , и правила #2 и #3 будут обработаны в любом случае (и #1 тоже, но больше ничего не делает).В вашем примере, если вы хотите предотвратить перенаправление
/bar
на/qux
, когда он был переписан первым RewriteRule, вы можете использоватьRewriteRule foo bar [L] RewriteCond %{THE_REQUEST} ^GET\ /bar RewriteRule bar qux
Который перепишет
/bar
на/qux
только , если пользователь специально запросил/bar
, а не если URL был переписан с/foo
на/bar
сначала.Фокус здесь в том, что
%{THE_REQUEST}
содержит точный заголовок HTTP, который был использован для запроса, и не изменяется при перезаписи URL, поэтому с помощью этой переменной вы всегда можете проверить, для чего исходил запрос (в отличие от%{REQUEST_URI}
, который меняется при каждой перезаписи).
Из
mod_rewrite
введение :Обязательно настройте уровень журнала mod_rewrite на один из уровней трассировки уровни, использующие директивуLogLevel . Он незаменим в проблемы отладки с конфигурацией mod_rewrite, так как она расскажет вы точно знаете, как обрабатывается каждое правило.
Для включения трассировки mod_rewrite в Apache 2.4 можно использовать
LogLevel info mod_rewrite:trace3
Однако в Apache 2.2 (который является текущим фаворитом для производства) вы придется использовать
RewriteLog "/var/log/apache2/rewrite.log" RewriteLogLevel 3
Ваша конфигурация
RewriteRule foo bar [L] RewriteRule bar qux
Проблематично, потому что он должен быть запущен только один раз, чтобы работать так, как вы хотите. Флаг L в 2.2 не делает того, что вы думаете, когда правило используется в Каталоге или .контекст htaccess.
Если вы используете RewriteRule в любом из них .файлы htaccess или в разделы, важно иметь некоторое понимание как обрабатываются правила. Упрощенная форма этого заключается в том, что когда-то правила были обработаны, то переписанный запрос передается обратно механизм синтаксического анализа URL, чтобы сделать то, что он может с ним. Вполне возможно, что поскольку переписанный запрос обрабатывается, то .файл htaccess или раздел может быть обнаружен снова, и таким образом набор правил может быть запущен опять с самого начала. Чаще всего это произойдет, если один из правила вызывают перенаправление-либо внутреннее , либо внешнее, - вызывающее запросите процесс, чтобы начать все сначала.
Однако перемещение этих правил в конфигурацию службы или виртуальный хост контекст действительно работает. (Проверено на моем локальном сервере.)
В общем случае вы хотите написать правила, так что не имеет значения, сколько раз они обрабатываются. Если вы абсолютно не можете этого сделать, мне все еще не нравится использовать
RewriteCond %{THE_REQUEST} ^GET\ /bar
, чтобы избежать зацикливания или дажеRewriteCond %{THE_REQUEST} ^[^ ]+ /bar
, но у меня нет предложения на данный момент для Apache 2.2.Apache 2.4 имеет флагEND как раз для этой ситуации.