Правило Apache 2.4 mod_rewrite, применяющее перенаправление к правилу без перенаправления (только флаг [L])

Итак, у меня возникает эта сумасшедшая проблема с 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, которая могла бы вызвать это?

2
задан 11 January 2019 в 01:02
1 ответ

«Проблема» в том, что процесс перезаписи не заканчивается, когда он достигает последней директивы в каталоге контексте ( .htaccess ?) . Процесс перезаписи начинается заново и повторяется до тех пор, пока URL-адрес не пройдет без изменений или не произойдет перенаправление.

Итак, что происходит, когда вы запрашиваете http://app.example.com/AllowThisUri/Http :

  1. Первоначальное перенаправление действительно пропускается из-за условия , которое явно исключает этот один URL.
  2. Запрос внутренне переписан на индекс. php по последнему правилу.

Теперь процесс перезаписи начинается заново с перезаписанным URL (например, http://app.example.com/index.php ):

  1. http://app.example.com/index.php "перенаправляется" на https://app.example.com/index.php по первому правилу. Из-за флага L текущий цикл обработки останавливается (т. Е. Оставшиеся 2 правила перезаписи пропускаются).

  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]
0
ответ дан 3 December 2019 в 14:24

Теги

Похожие вопросы