Итак, у меня возникает эта сумасшедшая проблема с apache 2.4 / CentOS7 с веб-интерфейсом. app.
Я хочу перенаправить все незащищенные URL-адреса в домене приложения на защищенные версии, ЗА ИСКЛЮЧЕНИЕМ для одного URI (конечная точка веб-перехватчика для режима песочницы поставщика - нет действительного сертификата SSL, так как это не рабочий процесс, поэтому мы должны разрешить HTTP В дополнение к домену приложения существуют домены клиентских сайтов, которые также проходят через него, поэтому мы НЕ хотим, чтобы они перенаправлялись, поскольку ни у одного из них нет SSL, поэтому мы явно сопоставляем HTTP_HOST.
Это шаблон фронт-контроллера, мы хотите, чтобы index.php
обрабатывал все эти запросы к файлам и каталогам для всех доменов и через SSL только для домена приложения.
Это КАЖЕТСЯ так просто:
RewriteEngine on
RewriteBase "/"
# Redirect all app domain urls to ssl
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} "^app\.example\.com$" [NC]
RewriteCond %{REQUEST_URI} "!^/AllowThisUri/Http"
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# I had to split this -d rule off of the -f rule to account for custom
# domain homepages from not being routed to the front controller when
# transitioning from centos6/apache2.2 for some reason
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} "!^/$"
RewriteRule "^(.*)$" index.php [L]
# Redirect non-files to entry script
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule "^(.*)$" index.php [L]
Но что происходит это когда я тестирую с помощью
curl http://app.example.com/AllowThisUri/Http
. Последнее правило, которое передается в index.php
, используется, но вместо того, чтобы фактически обрабатываться в dex.php
, он перенаправляет туда ... curl возвращает (сокращенный ответ)
<title>301 Moved Permanently</title>
<p>The document has moved <a href="https://app.example.com/index.php">here</a>.</p>
Итак, если я закомментирую это новое исключение RewriteCond
:
#RewriteCond %{REQUEST_URI} "!^/AllowThisUri/Http"
Произойдет ожидаемая вещь, она перенаправит на тот же URL, за исключением https:
<title>301 Moved Permanently</title>
<p>The document has moved <a href="https://app.example.com/AllowThisUri/Http">here</a>.</p>
Если я полностью удалю перенаправление на логику HTTPS, я получу ответ от фронт-контроллера, которого я ожидал (он просто печатает «привет» для тестирования).
#RewriteCond %{HTTPS} off
#RewriteCond %{HTTP_HOST} "^app\.example\.com$" [NC]
#RewriteCond %{REQUEST_URI} "!^/AllowThisUri/Http"
#RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Итак, я вставил все обратно - точно так, как мы начали, и могу изменить R = 301
на 302
следующим образом:
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=302,L]
и, конечно же, это изменит плохой неожиданный ответ перенаправления:
<title>302 Found</title>
<p>The document has moved <a href="https://app.example.com/index.php">here</a>.</p>
Надеюсь, это имеет смысл. Объяснять, прошу прощения, многословно.
Я вижу, хотя условие ! ^ / AllowThisUri / Http
соответствует, и мы пропускаем правило перенаправления HTTPS, и правила продолжают обрабатываться к тому времени, когда оно доходит до отправки последнего правила это в index.php
, похоже, что часть перенаправления RULE IT SKIPPED как-то зависает и влияет на результат. Для меня это не имеет абсолютно никакого смысла.
Повторюсь, без исключения одного URI с RewriteCond
, перенаправления без SSL на ssl работают должным образом. Чтобы полностью удалить всю эту логику перенаправления, фронт-контроллер index.php
отвечает ожидаемым ответом. Когда мы добавляем этот дополнительный RewriteCond
, чтобы исключить один URI, он ведет себя некорректно / неожиданно и возвращает перенаправление TO index.php
вместо его обработки и возвращает ожидаемый ответ от фронт-контроллера.
Может быть, кто-то знает о каких-то непонятных настройках или, может быть, об Apache 2.4, которая могла бы вызвать это?
«Проблема» в том, что процесс перезаписи не заканчивается, когда он достигает последней директивы в каталоге контексте ( .htaccess
?) . Процесс перезаписи начинается заново и повторяется до тех пор, пока URL-адрес не пройдет без изменений или не произойдет перенаправление.
Итак, что происходит, когда вы запрашиваете http://app.example.com/AllowThisUri/Http
:
индекс. php
по последнему правилу. Теперь процесс перезаписи начинается заново с перезаписанным URL (например, http://app.example.com/index.php
):
http://app.example.com/index.php
"перенаправляется" на https://app.example.com/index.php
по первому правилу. Из-за флага L
текущий цикл обработки останавливается (т. Е. Оставшиеся 2 правила перезаписи пропускаются).
Поскольку было запущено перенаправление (код ответа 3xx), процесс перезаписи не выполняется. запускается заново, и отправляется ответ перенаправления.
Одно из решений - запускать перенаправление только для прямых запросов от клиента, а не перезаписанных запросов (на index.php
). Для этого мы можем добавить к перенаправлению дополнительное условие, которое проверяет переменную среды REDIRECT_STATUS
. Эта переменная изначально пуста и после первой успешной перезаписи ей присвоено значение «200».
Например:
# Redirect all app domain urls to ssl
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} "^app\.example\.com$" [NC]
RewriteCond %{REQUEST_URI} "!^/AllowThisUri/Http"
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
(Небольшая уборка ... нет необходимости захватывать шаблон RewriteRule
если обратная ссылка не используется.)
Если есть только 1 URL, который вы хотите исключить, то более эффективно проверить это в шаблоне RewriteRule
, вместо использования условия и проверка по переменной сервера REQUEST_URI
(если этот же URL не используется и для других имен хостов?). Например:
# Redirect all app domain urls to ssl
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^app\.example\.com$ [NC]
RewriteRule !^AllowThisUri/Http https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]