Назад | Перейти на главную страницу

.HTACCESS создает ненужную цепочку переадресации 301 - как удалить?

Мой стек:

Исходная информация:

Недавно я запустил новый сайт для клиента. В процессе редизайна мы решили:

Пример СТАРОГО URL:
http://www.example.com/courses/acme-course.php

Пример НОВОГО URL:
https://www.example.com/courses/acme-course

Моя проблема:

Ненужное дополнительное перенаправление 301 происходит, когда пользователь переходит на один из СТАРЫХ URL-адресов.

Я не понимаю, почему создается дополнительное перенаправление 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

2ND 301 Redirect (правильный конечный целевой 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.
  1. Удаление .php на самом деле не выполняется вашим .htaccess директивы ?! Я предполагаю, что это должно быть сделано логикой вашего приложения / CMS? Следовательно, это будет всегда приведет ко второму перенаправлению (поскольку .htaccess перенаправляет на HTTPS по тому же URL-пути). Вам нужно сделать что-то вроде следующего в верхней части вашего .htaccess файл, чтобы удалить .php расширение.

    RewriteRule (.+)\.php$ https://www.example.com/$1 [R=301,L]
    

ОБНОВИТЬ: Если я изменю порядок правил / условий, останется ли мое размещение Options + FollowSymlink на прежнем уровне?

Это не имеет значения где то Options возникает директива. Однако логично (с точки зрения удобочитаемости) располагать его в верхней части. (Директивы Apache не обязательно выполняются в том порядке, в котором они указаны в файле конфигурации, поскольку каждый модуль работает независимо.)

Предполагая, что вы вручную кодируете свой .htaccess файл, то его можно привести в порядок ...

  1. Нет необходимости в (нескольких) <IfModule mod_rewrite.c> обертки. Mod_rewrite необязателен? Ваш сайт будет перенесен на несколько серверов, где mod_rewrite не включен?

  2. Нет необходимости в нескольких 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, это на самом деле не применимо. (Хотя этот env var может по-прежнему использоваться вашим приложением.)

  • Редко следует использовать NC флаг при отрицательном условии. Поэтому я убрал его из условия !^www\.. Вы хотите, чтобы он перенаправлял, когда хост не запускается с www. - все строчные. С NC флаг, что он не сможет перенаправить WwW. - хотя это все равно было бы очень редко.

  • Я удалил ненужную проверку HTTPS при каноническом перенаправлении www.

  • В PT флаг на последнем RewriteRule не требуется в .htaccess. В .htaccess это поведение по умолчанию (сквозное).

  • Перед тестированием вам необходимо очистить кеш браузера, так как ошибочные перенаправления 301, скорее всего, были кэшированы браузером. По этой причине рекомендуется протестировать 302 (временных) перенаправления.