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

Почему я получаю двойную косую черту в конце в зависимости от того, где находится мое RewriteRule?

Я использую следующий код, чтобы направлять все запросы www на URL-адреса без www:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.org$ [NC]
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]

Это прекрасно работает внутри файла .htaccess в корне моего веб-сайта.
Например,
www.example.com -> example.com/
www.example.com/ -> example.com/
www.example.com/other_page -> example.com/other_page

Однако, если я перенесу этот же код в конфигурацию VirtualHost, переписанные URL-адреса будут содержать двойную косую черту в конце.
www.example.com -> example.com//
www.example.com/ -> example.com//
www.example.com/other_page -> example.com//other_page

Я исправил это, убрав косую черту из правила перезаписи:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.org$ [NC]
RewriteRule ^(.*)$ http://example.com$1 [R=301,L]

Но я не могу понять причину этого. Кто-нибудь знает почему?

Насколько я понимаю, в файлах .htaccess строка, которую mod_rewrite обрабатывает в вашем правиле, относится к каталогу, в котором находится файл .htaccess, поэтому в начале у нее не будет /.

В записи VirtualHost строка, которую он обрабатывает, является абсолютной для корня сервера и, следовательно, включает /.

Это создает тонкие различия в том, как работает mod_rewrite.

Вот кто-то с похожей проблемой и ее решение:

http://forum.modrewrite.com/viewtopic.php?p=56322&sid=77f72967f59200b5b5de174440234c3a

Это должно работать в обоих случаях, если я правильно помню свой побег:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.org$ [NC]
RewriteRule ^\/?(.*?)$ http://example.com/$1 [R=301,L]

Это происходит из-за того, что вы захватываете начальную косую черту с помощью (.*) а затем применив еще одну косую черту перед ним в новом месте /$1. Раньше этого не происходило, потому что mod_rewrite ведет себя немного иначе при работе в контексте каталога, а не в контексте сервера.

Вы можете избежать этого, опционально прервав косую черту. Кроме того, вы можете использовать RedirectMatch в пустом VirtualHost с вашими избыточными доменами, что немного меньше обрабатывает и может выглядеть чище.

<VirtualHost *>
ServerName example.com
ServerAlias other.example.com
..
RedirectMatch permanent ^/?(.*) http://example.com/$1
</VirtualHost>

Я включаю этот пост для полноты картины.

В Документация Apache объясняет, почему такое поведение происходит очень хорошо, и является причиной существования директивы RewriteBase.

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

Пример:

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.example\.org$ [NC]
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]

Из документации Apache 2.2 mod_rewrite:

Директива RewriteBase явно устанавливает базовый URL-адрес для перезаписи для каждого каталога.

Мое практическое правило - почти всегда использовать RewriteBase в файлах .htaccess, а не использовать его в конфигурации Apache.

У меня не было времени разбираться с этой проблемой, поэтому просто перепишите // на / :)

RewriteCond %{THE_REQUEST} //
RewriteRule ^(.*)$ http://domain.com [R=301,L]