Dlaczego otrzymuję podwójny ukośnik w zależności od tego, gdzie znajduje się moja RewriteRule?

9

Korzystam z następującego kodu, aby kierować wszystkie żądania www na adresy URL inne niż www:

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

Działa to świetnie w pliku .htaccess w katalogu głównym mojej witryny.
Na przykład
www.example.com -> example.com/
www.example.com/ -> example.com/
www.example.com/other_page -> example.com/other_page

Jeśli jednak przeniosę ten sam kod do mojej konfiguracji VirtualHost, przepisane adresy URL zawierają podwójny ukośnik.
www.example.com -> example.com//
www.example.com/ -> example.com//
www.example.com/other_page -> example.com//other_page

Naprawiłem to, usuwając ukośnik z reguły przepisywania:

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

Ale nie mogę zrozumieć przyczyny tego. Czy ktoś wie dlaczego?

davekaro
źródło

Odpowiedzi:

10

Jak rozumiem, w plikach .htaccess ciąg przetwarzany przez mod_rewrite w regule jest względny w stosunku do katalogu, w którym znajduje się plik .htaccess, więc nie będzie miał / na początku.

We wpisie VirtualHost ciąg, który przetwarza, jest bezwzględny dla katalogu głównego serwera, a zatem zawiera /.

Powoduje to subtelne różnice w działaniu mod_rewrite.

Oto ktoś z podobnym problemem i rozwiązaniem:

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

Powinno to działać w obu przypadkach, zakładając, że pamiętam moją ucieczkę poprawnie:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.org$ [NC]
RewriteRule ^\/?(.*?)$ http://example.com/$1 [R=301,L]
Neobajt
źródło
Dzięki! Teraz przynajmniej rozumiem dlaczego. Czy jest to jednak lepsze z jakiegoś powodu niż usunięcie / przed 1 $, jak pokazałem w moim pierwotnym pytaniu?
davekaro
1
Nie ma nic lepszego ani gorszego, jest to tylko blok, który można przełączać między .htaccess VirtualHost bez konieczności jego edycji za każdym razem, aby poradzić sobie z różnicami kontekstu. Jeśli twoja droga Ci odpowiada, trzymaj się jej! :)
Neobyte
Och, właśnie tak - twoja metoda będzie działać zarówno w .htaccess, jak i VirtualHost. To sprawia, że ​​lepiej IMO :)
davekaro
4
Miałem dokładnie taki sam problem jak @davekaro i wypróbowałem twoje rozwiązanie. Ostatnia linia nie działała dla mnie. RewriteRule ^/?(.*)$ http://example.com/$1 [R=301,L]wykonał lewę.
Kenny Rasschaert
2

Dzieje się tak, ponieważ przechwytujesz początkowy ukośnik, (.*)a następnie nakładasz inny ukośnik przed nim w nowej lokalizacji /$1. Nie zdarzyło się to wcześniej, ponieważ mod_rewrite zachowuje się nieco inaczej podczas pracy w kontekście dla poszczególnych katalogów, w przeciwieństwie do kontekstu dla jednego serwera.

Można tego uniknąć, opcjonalnie uprzedzając slash. Dodatkowo możesz użyć RedirectMatch w pustym VirtualHost ze swoimi nadwyżkowymi domenami, co zapewnia nieco mniej przetwarzania i może wyglądać czystiej.

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

Dan Carley
źródło
Miły. Lubię podejście RedirectMatch. Prawdopodobnie pójdę z tym, ponieważ to naprawdę jest przekierowanie, które chcę osiągnąć.
davekaro
1

Załączam ten post dla kompletności.

Dokumentacja Apache wyjaśnia, dlaczego takie zachowanie występuje bardzo dobrze i jest przyczyną istnienia dyrektywy „RewriteBase”.

Po prostu włączenie dyrektywy „RewriteBase” do pliku .htaccess powinno osiągnąć pożądany rezultat.

Przykład:

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

Z dokumentacji mod_rewrite Apache 2.2:

Dyrektywa RewriteBase jawnie ustawia podstawowy adres URL do przepisywania poszczególnych katalogów.

Moją ogólną zasadą jest prawie zawsze używanie „RewriteBase” w plikach .htaccess, a nie używanie go w konfiguracji Apache.


źródło
0

Nie miałem czasu poradzić sobie z tym problemem, więc po prostu przepisz // do / :)

RewriteCond %{THE_REQUEST} //
RewriteRule ^(.*)$ http://domain.com [R=301,L]
użytkownik956584
źródło