
В моем виртуальном хосте для SSL-подключений есть следующее (мой виртуальный хост без SSL выглядит так же, но без первого набора правил для перенаправления).
DocumentRoot /var/www/example.com/public/
<Directory "/var/www/example.com/public/">
#only mod_rewrite configuration is shown here
RewriteEngine on
RewriteBase /
RewriteCond $1 !=signup
RewriteCond $1 !=login
RewriteCond $1 !=welcome
RewriteCond $1 !=thankyou
RewriteRule ^(.*)$ http://example.com/$1 [L,R,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteRule ^(.+)$ index.php?q=$1 [L,QSA]
</Directory>
Моя цель — перенаправить любой несоответствующий запрос страницы (регистрация|вход|приветствие|спасибо) на виртуальный хост без SSL без дальнейшей обработки, в противном случае не перенаправлять, а обрабатывать запрос на виртуальном хосте SSL.
Первый набор RewriteRule отвечает за перенаправление, а второй набор RewriteRule — за обычную обработку страницы.
Без первого набора правил все запросы загружаются корректно под виртуальным хостом SSL.
При первом наборе правил перенаправления работают нормально, если они не соответствуют перечисленным ресурсам. Например, запрос на
https://example.com/about
перенаправляет на
http://example.com/about
Но при запросе страниц регистрации, входа, приветствия и благодарности возникает проблема. Эти запросы также перенаправляются на сайт без ssl, но в сломанной манере. Запрос на
https://example.com/signup
перенаправляет на
http://example.com/index.php?q=signup
Похоже, что первый набор правил остается не сопоставленным (как и ожидалось), а затем после обработки второго набора правил снова применяется первый набор правил (не ожидалось).
Я не могу сопоставить это неожиданное поведение с какой-либо документированной функциональностью.
Есть идеи?
Редактировать
Я нашел несколько неясных ссылок в документации на то, что Apache перезапускает правила, когда совпадение правил происходит в "контексте каталога", однако ссылка была относительно .htaccess. Моя перезапись происходит внутри тега <Directory> внутри моего тега <VirtualHost>. В настоящее время я тестирую перемещение перезаписывания за пределы контекста <Directory> - это, конечно, похоже, меняет поведение, но я пока не заставил это работать так, как мне нужно.
Редактировать2
Проблема, безусловно, вызвана тем, что Apache перезапускает обработку перезаписи, когда обработка правила существует в контексте каталога. Я переместил обработку правила за пределы тега <Directory>. Однако теперь строки RewriteCond не работают... например.
RewriteCond %{REQUEST_FILENAME} -f
потому что apache еще не разрешил запрошенный ресурс для сопоставления файла с помощью DocumentRoot. Какой беспорядок.
Итак, я затем вручную добавляю значение, которое я указал в DocumentRoot, к RewriteCond. Однако это кажется плохим хаком. Например.
RewriteCond /var/www/example.com/public%{REQUEST_FILENAME} -f
Итак, теперь я ищу способ запретить Apache перезапускать процесс перезаписи в контексте каталога или, что еще лучше, лучший способ указать необходимые RewriteConds на уровне <VirtualHost>.
решение1
Предлагаю добавить следующее в вашу конфигурацию, что даст вам подробный лог того, что делает mod_rewrite и почему. Это может помочь прояснить, почему у вас такое поведение:
RewriteLog /tmp/rewrite.log RewriteLogLevel 9
После того как вы закончите анализ, обязательно удалите эти строки, так как они влияют на производительность.
решение2
Я остановился на следующем решении, разместив перезаписи вне разделов <Directory ...>. Это позволяет мне перенаправлять любые запросы, которые не должны быть SSL, на сайт без SSL, в то же время позволяя любому статическому контенту обслуживаться через SSL (изображения, css, js и т. д.).
<VirtualHost ...>
...
RewriteEngine on
RewriteCond $1 !=signup
RewriteCond $1 !=login
RewriteCond $1 !=welcome
RewriteCond $1 !=thankyou
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/(.*)$ http://example.com/$1 [R=303,QSA,L]
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/robots.txt
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-d
RewriteRule ^/(.+)$ /index.php?q=$1 [QSA,L]
...
</VirtualHost>