0,0
рейтинг
20 ноября 2009 в 15:14

Разработка → mod_rewrite: Просмотр списка правил только один раз

С mod_rewrite есть одна проблема, об которую набиты уже наверное 15 миллионов шишек: он просматривает список правил снова и снова, пока URL удается хоть как-то изменить.

Очень часто получаеются и бесконечные циклы(например добавление расширения — оно добавляется снова и снова, если специально регэкспом не ограничить), над которыми с непривычки приходится поломать голову. Все надежды на модификатор [L] тщетны — он лишь сразу запускает следующую иттерацию обработки. Да и без бесконечного цикла лишние иттерации скорости работы не добавляют :-)

Хочу поделится достаточно простым и универсальным средством борьбы с такой особенностью, который обнаружил только-что :-)


RewriteCond %{ENV:REDIRECT_FINISH} !^$
RewriteRule ^ - [L]

#Дальше сколько угодно правил
RewriteRule ^/?page/([a-z]+)$ read.php?page=$1 [E=FINISH:1,L,QSA]
RewriteRule ^.*$ 404.php [E=FINISH:1,L]


Что тут происходит? Как только мы произвели окончательное преобразование URL-а — выставляем переменную окружения FINISH, и на следующей иттерации Апач скопирует старые перменные окружения с префиксом REDIRECT_, увидет установленный REDIRECT_FINISH и закончит работу. Телемаркет :-)

PS: Встроенный rewrite-engine в nginx лишен этой проблемы с рождения, но это так, к слову ;-)

UPDATE: В коментах предолжили еще короче, с безусловным обрубанием всего после первой иттерации:

# Don't loop.
RewriteCond %{ENV:REDIRECT_STATUS} !^$
RewriteRule .* — [L]
Михаил Сваричевский @BarsMonster
карма
965,7
рейтинг 0,0
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (21)

  • +4
    просто вы не умеете их готовить :)
    • 0
      Я то умею, лет 7 уже их пишу время от времени, а вот тем кто впервые сталкивается — бывает сложновато :-)
  • +3
    А у mod_rewrite есть log и debug ;)
    • 0
      Есть, но это не избавляет от необходимости руками писать такие регекспы, которые бы в конце концев приводили бы к «устойчивому урлу», это просто дополнительная, и часто ненужная работа.
  • +9
    # Don't loop.
    RewriteCond %{ENV:REDIRECT_STATUS} !^$
    RewriteRule .* — [L]
    • 0
      Интересное решение, более жесткое, в моём варианте часть правил можно отправить на второй проход, хотя ваш для большинства случаев подойдет :-)
  • 0
    Почему бы просто не писать однозначные правила, которые будут переписывать только то, что нужно?
    • 0
      Потому что для этого нужны дополнительные усилия мозга:

      RewriteRule ^/?page/(.*)$ /page/read.php?page=$1 [E=FINISH:1,L,QSA]

      Как вы это перепишите однозначно?
      • –1
        Мозг для того и нужен, чтобы не использовать конструкции типа (.*)
        • +2
          Это просто пример. В любом случае, не вижу проблем с (.*) если это действительно нужно.
          • 0
            Это я к тому, что (.*) и вызывает зацикливание. Не знаю, когда это может быть действительно нужно, но от такой маски ещё и производительность сильно страдает.
            • 0
              Как тогда прикажете FrontController делать?
            • 0
              И мне кажется вы переоцениваете сложность этого регэкспа. Готов поспорить, даже на 10'000 запросах в секунду Апач не упрется в этот регэксп :-)
  • 0
    О! Я нашёл это :)))
    Спасибо огромное
  • +1
    а я в последнее время использую что-то типа

    RewriteEngine On
    RewriteBase /

    RewriteRule ^(.*).png$ $1.png [E=redir:yes,L]
    RewriteRule ^(.*).gif$ $1.gif [E=redir:yes,L]
    RewriteRule ^(.*).jpg$ $1.jpg [E=redir:yes,L]
    RewriteRule ^(.*).css$ $1.css [E=redir:yes,L]
    RewriteRule ^(.*).js$ $1.js [E=redir:yes,L]

    RewriteCond %{ENV:REDIRECT_redir} !^yes$
    RewriteRule .* index.php [L]

    то есть, все (за исключениями понятно чего) летит в индекс, а дальше уже разгребаю что прилетело в скрипте, мне почему-то так спокойнее
    • +4
      шаблон называется FrontController
    • +8
      RewriteRule ^(.*).(png|gif|jpg|css|js)$ $1.$2 [E=redir:yes,L]
      • 0
        Ну вообще-то файл еще существовать должен.
        • +2
          RewriteEngine On
          RewriteCond   %{REQUEST_FILENAME}       !-d
          RewriteCond   %{REQUEST_FILENAME}       !-f
          RewriteRule   ^(.*)                                             index.php?%{QUERY_STRING}
          
  • 0
    О ЧЕЛОВЕЧИЩЕ! Я не знаю как высказать свою благодарность тебе! Я вскипятил себе мозг 10 раз пока не увидел это! Примите все возможные и невозможные способы благодарности от меня.
    • 0
      Спасибо :-)

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