Я удаляю .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
Мои текущие проблемы:
.php
версия страниц не 301 редирект..php
и не .php
версии страниц доступны для просмотра.Вот мой код:
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 в родительской конфигурации (каталог контекст).