С приведенными ниже изменениями в htaccess, как и ожидалось, этот запрос HTTPS не переписано:
https://example.com/system/anything
не является переписан на
http://example.com/system/anything
Но неожиданно этот HTTPS-запрос переписывается:
https://example.com/preview/anything
является переписан на
http://example.com/index.php/preview/anything
Почему это?
Еще пара фактов / наблюдений:
/system/
это фактический путь на сервере. Но /preview/
не является фактическим путем - это сегмент URL, который имеет смысл в CMS, например, /index.php/preview/anything
как CMS получает запрос на /preview/anything
URL.
Другие несистемные URL-адреса перезаписываются правильно (с HTTPS на HTTP) и правильно передаются в index.php. Например.,
https://example.com/real
является переписан на
http://example.com/real
Вот полный блок правил:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# Force HTTPS for System URLs
RewriteCond %{REQUEST_URI} ^/system(.*)$ [NC]
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ "https://example.com/$1" [R=301,L]
# Force HTTP for Other URLs, but not: system or preview
RewriteCond %{REQUEST_URI} !^/(system|preview)/(.*)$ [NC]
RewriteCond %{HTTPS} =on
RewriteRule ^(.*)$ "http://example.com/$1" [R=302,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php/$1 [L]
</IfModule>
Любое понимание того, почему /preview/
получает странное обращение?
Добавлено: Обратите внимание, что /preview/anything
получает 302
перенаправить на /index.php/preview/anything
- и ЭТО большая часть того, что кажется таким странным / неожиданным. В окончательном правиле не должно быть перенаправления, просто переписывание.
Эти правила перезаписи в .htaccess
файл? В таком случае в [L]
флаг не делает то, что вы думаете- он останавливает обработку текущего набора правил, но затем запрос снова обрабатывается Apache, используя .htaccess
файлы, подходящие для перезаписанного URI, поэтому ваши правила могут быть выполнены снова. Этого не происходит для правил, которые находятся в файле конфигурации Apache (а не внутри <Directory>
раздел) - в этом случае [L]
flag обрабатывается должным образом.
Для вашего примера, https://example.com/preview/anything
внутренне переписан на https://example.com/index.php/preview/anything
по третьему правилу; однако для обработки этого запроса Apache должен прочитать .htaccess
файл снова - и на этот раз URI соответствует вашему второму правилу, которое возвращает 302
перенаправить.
Apache 2.4.x поддерживает [END]
флаг, который останавливает такие циклы перезаписи, в отличие от [L]
; решения для более ранних версий Apache более сложны.
Если вы хотите убедиться, что Apache выполняет только один проход по вашим правилам перезаписи, вы можете добавить следующее правило перед всеми остальными:
RewriteCond %{ENV:REDIRECT_STATUS} !=""
RewriteRule ^ - [L]
На первом проходе REDIRECT_STATUS
будет пусто; на втором проходе он будет иметь непустое значение (обычно 200
), и правило будет соответствовать и действительно прекратит дальнейшие перезаписи.
В случае, если такое правило не подходит (например, в некоторых случаях вам нужно обрабатывать перезаписанные URI на втором проходе), вы можете установить переменную среды в правилах, которые должны быть действительно окончательными:
RewriteRule ^(.*)$ /index.php/$1 [L,E=FINISH:1]
и добавьте следующее правило перед всеми остальными:
RewriteCond %{ENV:REDIRECT_FINISH} !=""
RewriteRule ^ - [L]
Обратите внимание, что во время второго прохода Apache добавляет REDIRECT_
к именам переменных среды, которые были определены во время первого прохода, поэтому вам необходимо установить FINISH
, но тест REDIRECT_FINISH
.
В качестве альтернативы вы можете попытаться изменить условия сопоставления так, чтобы на втором проходе URI, измененные на первом проходе, не совпадали (например, вставьте (index\.php/)?
в регулярное выражение во втором правиле).
Это http
схема (вместо https
) что тебя беспокоит? Если это так, вам следует посмотреть на RewriteBase
директива.
В
RewriteBase
директива определяет префикс URL, который будет использоваться для каждого каталога (htaccess)RewriteRule
директивы, заменяющие относительный путь.Эта директива требуется, когда вы используете относительный путь в подстановке в контексте для каждого каталога (htaccess) (...)
Похоже, последнее правило вводит абсолютное http
перенаправление на основе, когда оно выполняется, возможно, из-за какой-либо ошибки или функции в Apache или mod_rewrite.
Как насчет того, чтобы разбить это на два правила с дополнительным условием?
Попробуй это:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTPS} =off
RewriteRule ^(.*)$ http://example.com/index.php/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTPS} =on
RewriteRule ^(.*)$ https://example.com/index.php/$1 [L]
Я не думаю, что вам нужен '(. *) $' В конце операторов RewriteCond, потому что вы нигде не используете захваченные данные. Вы можете упростить эти 2 так:
RewriteCond %{REQUEST_URI} ^/system [NC]
и RewriteCond% {REQUEST_URI}! ^ / (system | предварительный просмотр) / [NC]
Я бы также порекомендовал включить RewriteLog и установить RewriteLogLevel, чтобы точно видеть, что apache делает для каждого запроса. С apache 2.2 или ниже это будет:
RewriteLog /var/log/apache2/rewrite.log
RewriteLogLevel 7
Вы должны шаг за шагом увидеть, какие именно совпадения и какие действия предпринял apache.