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

Почему 301 Redirect не работает после удаления расширения .PHP через HTACCESS?

Я удаляю .php расширение из файлов, содержащихся в определенном каталоге на моем веб-сайте (courses) через .htaccess на Apache / 2.2.26 (Unix).

Кроме того, я хотел бы 301 перенаправить старый .php версия на версию без PHP.

Старая структура URL:

http://www.example.com/courses/blue-course.php

Новая структура URL:

http://www.example.com/courses/blue-course

Мои текущие проблемы:

Вот мой код:

RewriteEngine On

# External Routing
RewriteCond %{REQUEST_URI} (.*\/courses\/)([^\s]+)\.php [NC]
RewriteRule (.*courses\/)([^\s]+)\.php http://www.example.com/$1$2 [L,R=301]

# Internal Routing
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [L]

Вместо того, чтобы «вообще не выполнять 301 перенаправление», я ожидал бы, что ваш код создаст цикл перенаправления. Поскольку более раннее перенаправление также перехватывает перезаписанный URL (более поздней директивой) и перенаправляет и т. Д. И т. Д.

не .php версия страниц не 301 редирект.

Не правда ли? Или здесь следует убрать «не» или «не»?

обе .php и не .php версии страниц доступны для просмотра.

Это может означать, что, возможно, включен режим MultiViews. Для правильного выполнения директив mod_rewrite необходимо отключить MultiView. (Вы либо используете MultiViews или mod_rewrite здесь, однако у вас могут возникнуть проблемы при попытке перенаправить если MultiViews включен.) Чтобы убедиться, что MultiViews отключен, добавьте следующее в верхней части .htaccess файл:

Options -MultiViews

Однако, чтобы избежать цикла перенаправления, вместо сопоставления с REQUEST_URI, который изменяется при перезаписи URL (то же самое, что и URL-путь, совпадающий с RewriteRule шаблон), вы должны либо сопоставить с THE_REQUEST (который содержит первую строку запроса и не изменяется) ИЛИ просто проверьте, что REDIRECT_STATUS переменная среды пуста, чтобы гарантировать, что вы проверяете только начальный запрос, а не перезаписанный запрос.

Например:

# External Routing
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.*courses\/)([^\s]+)\.php http://www.example.com/$1$2 [L,R=301]

NB: Всегда тест с 302 (временными) перенаправлениями, чтобы избежать проблем с кешированием.

Однако ваше регулярное выражение можно немного очистить. Согласно вашим примерам URL-адресов, /courses - это первый сегмент пути, однако ваше регулярное выражение соответствует "course /" в любом месте URL-пути. И вы разрешаете перенаправление любого URL-адреса с информацией о пути - это намеренно? Вам нужна только одна обратная ссылка; не два. И нет необходимости избегать косой черты в RewriteRule шаблон. Вам не обязательно нужна схема + имя хоста в замена строка, если у вас несколько доменов?

Так что, возможно, это можно было бы «упростить» до:

# External Routing
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(courses/[^\s]+)\.php$ /$1 [L,R=301]

# Internal Routing
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [L]

Это может сработать для конкретных URL-адресов, которые вы тестируете, однако это правило может легко нарушиться (и оно не нацелено конкретно на /courses подкаталог). %{REQUEST_FILENAME}.php не обязательно то же самое, что %{REQUEST_URI}.php. Таким образом, хотя условие может быть успешным, вы все равно можете переписать его на недопустимый URL-адрес, что может привести к бесконечному циклу - 500 Internal Server Error.

Например, учитывая запрос на /courses/blue-course/foo (на основе вашего примера), где /courses это каталог в файловой системе и blue-course.php это файл, который вы собираетесь перезаписать (нет подкаталога /blue-course) и /foo - это просто что-то, что было ошибочно добавлено к URL-адресу (возможно, даже злонамеренно третьей стороной), то это приведет к ошибке 500. Так как %{REQUEST_FILENAME}.php решает <document-root>/courses/blue-course.php (который существует), но %{REQUEST_URI}.php решает /courses/blue-course/foo.php (чего не существует). Затем процесс перезаписи начинается заново, что приводит к бесконечному циклу.

Эту проблему можно решить, изменив правило примерно так:

# Internal Routing
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule ^courses/ %{REQUEST_URI}.php [L]

Предполагая, что у вас нет нескольких расширений файлов или точек в базовом имени файла, например. blue-course.abc.php затем это также можно оптимизировать, убедившись, что запрошенный URL-адрес еще не имеет расширения файла (чтобы избежать тестирования каких-либо статических ресурсов). Например:

# Internal Routing
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule ^courses/ %{REQUEST_URI}.php [L]

В ! префикс на CondPattern отрицает его смысл.

В итоге

Options -MultiViews

RewriteEngine On

# External Routing
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(courses/[^\s]+)\.php$ /$1 [L,R=301]

# Internal Routing
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule ^ %{REQUEST_URI}.php [L]

Указанные выше директивы предполагают, что вы используете .htaccess в корневом каталоге документов вашего сайта. Однако, если вам нужно настроить таргетинг только на конкретный каталог и иметь минимальное количество других директив mod_rewrite, которые вам нужно унаследовать от родительских конфигураций, может быть полезно создать дополнительные .htaccess файл в этом подкаталоге, чтобы конфигурация оставалась отдельной. Однако директивы необходимо немного изменить:

RewriteEngine On

# External Routing
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^([^\s]+)\.php$ /courses/$1 [L,R=301]

# Internal Routing
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule ^ %{REQUEST_URI}.php [L]

Обратите внимание, что это (по умолчанию) полностью переопределит любые директивы mod_rewrite в родительской конфигурации (каталог контекст).