Некоторые поисковики (не будем показывать пальцем в гугл) считают ссылки вида http://site.com/InDex и http://site.com/index разными ссылками. Из-за этого можно натыкать ссылок на InDex на других сайтах, гугл их поиндексирует и найдет дубликат страницы у вас на сайте. (/me почесал затылок). По крайней мере, мне так рассказывали. Меня же во всей этой истории заинтересовало, что эту «проблему» можно пофиксить nginx-ом (интересно, а чего он вообще не умеет?).
Для всего этого ада нам понадобится nginx с perl-модулем (на lua я писать вообще не умею, даже копипастить lua не умею — так что моё решение на перле), точнее собранный с —with-http_perl_module
Я его обычно в пакете nginx-extras отыскиваю.
После установки правильного nginx-а кидаем в файл /etc/nginx/conf.d/99_lowercase.conf такую билиберду:
perl_set $uri_lowercase 'sub {
my $r = shift;
my $uri = $r->uri;
$uri = lc($uri);
return $uri;
}';
perl_set $args_lowercase 'sub {
my $r = shift;
my $args = $r->args;
$args = lc($args);
return $args;
}';
А в конфиг нужного сайта:
location ~[A-Z] { return 301 $scheme://$http_host$uri_lowercase?$args; }
Теперь все ссылки вида http://site.com/Admin?admin=Admin будут редиректить на http://site.com/admin?admin=admin (то бишь не конкретно сюда, а на туже ссылку, но в нижнем регистре).
Ок, а как быть с кириллицей? Если к примеру запрашивают http://site.com/Admin?admin=Админ ?
А вот хз, там же урлы когда-то декодятся, когда-то нет.
Для русских, имхо, проще заменой символа на символ пройти.
Так-то perl в наши времена вроде utf-compatible (достаточно use utf8; добавить в функции), но вот как завернуть if и location в эту функцию с учетом замены символов сходу непонятно. Попробуйте регулярки вида [А-Я], может заработают.
Получилось сделать с кириллицей, может быть кому-нибудь будет полезно.
perl_set $uri_lowercase ‘sub {
use Encode;
my $r = shift;
my $uri = $r->uri;
$uri = Encode::encode_utf8(lc(Encode::decode_utf8($r->uri)));
return $uri;
}’;
location / {
if ( $uri != $uri_lowercase ) {
rewrite ^(.*)$ $scheme://$host$uri_lowercase permanent;
}
index index.php;
}
А еще можно не собирать кому не хочется, а просто поставить эти пакеты.
apt install nginx-full nginx-extras
«Я его обычно в пакете nginx-extras отыскиваю. «
nginx-full и nginx-extras, кстати, вместе не поставятся, это конфликтующие пакеты.
Действительно конфликтуют. Я ставил nginx-extras и он работает. Спасибо за дополнение!
статья полезная, но давняя, хотя может кто и читает-отвечает еще. все это хорошо, если надо перевести все буквы, а если только в самом адресе, а параметры не трогать? например с http://site.com/Admin?admin=Admin на http://site.com/admin?admin=Admin ?
Так там сам кусок конфига состоит из двух частей, используйте только один.
> location ~[A-Z] { return 301 $scheme://$http_host$uri_lowercase?$args; }
Этот кусок отвечает только за uri.
> if ( $args ~ [A-Z] ) { return 301 $scheme://$http_host$uri?$args_lowercase; }
А этот за аргументы.
(только копируйте из поста, а не из комментария, лень верстать спецсимволы в комментарии)
спасибо. рад что Вы не бросаете старые статьи. и еще вопрос — а без дополнительного модуля нельзя ли это сделать? ибо очень не хочется пересобирать нгинкс.
> а без дополнительного модуля нельзя ли это сделать
«Для всего этого ада нам понадобится nginx с perl-модулем (на lua я писать вообще не умею, даже копипастить lua не умею — так что моё решение на перле), точнее собранный с —with-http_perl_module
Я его обычно в пакете nginx-extras отыскиваю. «
спасибо. извините за глупый вопрос. но если уж делать это в нгинксе с перлом, то не подскажете ли как добавлять конечные слэши при их отсутствии и заменять многократно повторяющиеся в разных местах адреса практически одним редиректом? сейчас конечный слэш добавляется в экспресс роутере, слэши заменяются в нгинксе, буквы, если сделать по статье, тоже будут в нгинксе. он если совпадет так что нет конечного слэша и либо большие буквы будут где не надо или несколько слэшей, то будет два редиректа — в нгинксе и в роутере. хотелось бы одним обойтись.
я бы и в роутере все сделал, но не получается адрес отловить как есть, а выражение не срабатывает.
> не подскажете ли как добавлять конечные слэши при их отсутствии
rewrite ^/([^?/.]+)(\?.*)?$ /$1/$2 redirect;
rewrite ^/([^?]+/[^?/.]+)(\?.*)?$ /$1/$2 redirect;
остальной текст комментария я не распарсил )
спасибо. извините, все в кучу слепил. если несколько слэшей подряд сделано. например site.ru/qwe//wwe///rt превратить в site.ru/qwe/wwe/rt/. а если в идеале то site.ru/qwE//wWe///rt превратить в site.ru/qwe/wwe/rt/ при том что есть еще и параметры site.ru/qwe/wwe/rt/?WER=yt&ff=Thy
если бы еще все сделать одним редиректом, а не по очереди в зависимости от условия пока пользователь добежит до страницы несколько редиректов пройдет. человеку это не заметно, а боты яндекса и гугла такое не приветствуют совсем..
Несколько слешей убрать можно так:
if ($request_uri ~ "^[^?]*?//") { rewrite "^" $scheme://$host$uri permanent; }
спасибо. если бы теперь это в одну кучу сложить как-то. ибо если через if, то много ветвей получается
Я не золотая рыбка =)
извините. это был риторический вопрос. премного благодарен за оказанную помощь. я пока пытаюсь это делать на express.router, чтобы не торгать нгинкс.
спасибо за оказанную теоретическую помощь и моральную поддержку. зная что есть запасной вариант, уже не так страшно было экспериментировать и у меня получилось сделать все в роутере, пока без повторных кавычек.
Да не за чт
Подскажите как исключить некоторые location, из редиректа на нижний регистр, к примеру http://somesite.ru/admin/* http://somesite.ru/dealer/* нужно что б в локейшенах редирект не отрабатывал
if ( $args ~ [A-Z] ) { return 301 $scheme://$http_host$uri?$args_lowercase; }
location ~[A-Z] { return 301 $scheme://$http_host$uri_lowercase?$args; }
Эти 2 строчки только в нужный location прописывайте.
Nginx поддерживает вложенные location.
Да, но как быть если нужно всего пару локейшенов исключить? не прописывать же мне их для каждого локейшена?
В плане?
для location / прописываете lowercase, для исключенных локаций отдельные секции без этих строк.