
Мой стек:
- ЛАМПА
- Апач/2.4.41
Исходная информация:
Недавно я запустил новый веб-сайт для клиента. В процессе редизайна мы решили:
- Перейти на HTTPS для всего сайта
- Удалите расширение .php из URL-адресов.
- Перейти на CMS
Пример СТАРОГО URL:
http://www.example.com/courses/acme-course.php
Пример НОВОГО URL:
https://www.example.com/courses/acme-course
Моя проблема:
При переходе пользователя на один из СТАРЫХ URL-адресов происходит ненужная дополнительная переадресация 301.
Я не понимаю, почему создается дополнительная переадресация 301, а не отправляет пользователя напрямую на правильный целевой URL с помощью одной переадресации 301.
Интересное наблюдение:
Ненужная дополнительная переадресация 301 не происходит, когда я использую СТАРЫЙ URL с HTTPS вместо HTTP.
Пример:
https://www.example.com/courses/acme-course.php
_
Использование указанного выше URL-адреса позволит правильно выполнить одинарную переадресацию 301 на правильный целевой URL-адрес:https://www.example.com/courses/acme-course
Вот пример цепочки перенаправлений 301:
Исходный URL-адрес запроса:
http://www.example.com/courses/acme-course.php
1ST 301 Перенаправление (необязательно):
ОТ:
http://www.example.com/courses/acme-course.php
К:
https://www.example.com/index.php?url=courses/acme-course.php
2-е перенаправление 301 (правильный конечный URL-адрес назначения):
ОТ:
https://www.example.com/index.php?url=courses/acme-course.php
К:
https://www.example.com/courses/acme-course
Мой код .htaccess:
# (1) General Settings
<IfModule mod_rewrite.c>
Options +FollowSymLinks
RewriteEngine On
</IfModule>
# (2) Force WWW
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=off
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{SERVER_ADDR} !=127.0.0.1
RewriteCond %{SERVER_ADDR} !=::1
RewriteRule ^ %{ENV:PROTO}://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
# (3) Force HTTPS
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
</IfModule>
# (4) URL Routing for CMS
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} =on
RewriteRule ^ - [env=proto:https]
RewriteCond %{HTTPS} !=on
RewriteRule ^ - [env=proto:http]
## Check if file/directory exists
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
## Route all other URLs to index.php/URL
RewriteRule ^(.*)$ index.php?url=$1 [PT,L,QSA]
</IfModule>
решение1
У вас есть две основные проблемы...
- Ваши директивы в неправильном порядке в
.htaccess
файле. Ваши HTTP-HTTPS- иwww
канонические перенаправления должны быть удаленыдоваш фронт-контроллер, который направляет URL в вашу CMS. Отсюда и неправильный внешний редирект на/index.php?url=courses/acme-course.php
- раскрывающий внутреннюю структуру URL CMS.
Удаление
.php
фактически не выполняется вашими.htaccess
директивами?! Я предполагаю, что это должно быть сделано вашей логикой приложения/CMS? Следовательно, это будетвсегдапривести к повторному перенаправлению (поскольку.htaccess
перенаправление на HTTPS по тому же URL-пути). Вам нужно сделать что-то вроде следующего в верхней части вашего.htaccess
файла, чтобы удалить.php
расширение.RewriteRule (.+)\.php$ https://www.example.com/$1 [R=301,L]
ОБНОВЛЯТЬ:Если я изменю порядок правил/условий, останется ли расположение Options +FollowSymlinks прежним?
Это не имеет значения.гдедиректива Options
появляется. Однако логично (с точки зрения читабельности) расположить ее в верхней части. (Директивы Apache не обязательно выполняются в том порядке, в котором они указаны в файле конфигурации, поскольку каждый модуль работает независимо.)
Если предположить, что вы вручную кодируете свой .htaccess
файл, то его можно привести в порядок...
Нет необходимости в (множественных)
<IfModule mod_rewrite.c>
оболочках. Является ли mod_rewrite необязательным? Будет ли ваш сайт перенесен на несколько серверов, где mod_rewrite не включен?Нет необходимости в нескольких
RewriteEngine
директивах.последнийпример на самом делепобедыи контролирует весь файл.Несколько
<IfModule>
блоковRewriteEngine
типичны для систем, которые автоматически редактируются кодом и/или предназначены для функционирования в нередактированном виде на нескольких серверах.
Итак, ваш .htaccess
файл следует переписать следующим образом в следующем порядке:
Options +FollowSymlinks
# Enable the rewrite engine...
RewriteEngine On
# ----------------------------------------------------------------------
# | Forcing `https://` |
# ----------------------------------------------------------------------
# Redirect to HTTPS on the "same host" (requirement for HSTS)
RewriteCond %{HTTPS} !=on
RewriteRule (.*) https://%{HTTP_HOST}/$1 [R=301,L]
# ----------------------------------------------------------------------
# | Forcing `www` |
# ----------------------------------------------------------------------
RewriteCond %{HTTP_HOST} !^www\.
RewriteCond %{SERVER_ADDR} !=127.0.0.1
RewriteCond %{SERVER_ADDR} !=::1
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# ----------------------------------------------------------------------
# | URL Routing for CMS |
# ----------------------------------------------------------------------
# (3)
RewriteCond %{HTTPS} =on
RewriteRule ^ - [env=proto:https]
RewriteCond %{HTTPS} !=on
RewriteRule ^ - [env=proto:http]
# (4) - Check if physical file exists
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# (5) - Rewrite all other URLs to index.php/URL
RewriteRule (.*) index.php?url=$1 [L,QSA]
Дополнительные замечания:
Переменная окружения
PROTO
содержит запрашиваемый протокол. С учетом порядка перенаправлений это всегда будет HTTPS. Причина этой переменной в том, что CMS может перенаправлять на HTTP, если осуществляется доступ к HTTP, или на HTTPS, если осуществляется доступ к HTTPS. Если вы принудительно используете HTTPS, то это на самом деле не применяется. (Хотя эта переменная окружения все еще может использоваться вашим приложением.)Редко следует использовать
NC
флаг в отрицательных условиях. Вот почему я удалил его из условия!^www\.
. Вы хотите, чтобы он перенаправлял, когда хост не начинается сwww.
- все строчные буквы. СNC
флагом перенаправление не произойдетWwW.
- хотя это в любом случае будет очень редким.Я удалил ненужную проверку HTTPS при каноническом перенаправлении www.
Флаг
PT
в последнемRewriteRule
не требуется в.htaccess
. В.htaccess
это поведение по умолчанию (проход).Вам нужно будет очистить кэш браузера перед тестированием, так как ошибочные перенаправления 301, скорее всего, были кэшированы браузером. По этой причине хорошей идеей будет провести тестирование с перенаправлениями 302 (временными).