Дубли страниц: как добавить или убрать завершающий слеш в конце URL


Проблема из-за слэша в конце URL

Неприятность относится к области SEO (поисковой оптимизации), а именно: к дублям страниц. В отличие от случая с дублированием по www, у этого варианта больше шансов остаться незамеченным. Часто внутренние подсистемы обработки запросов самописных (а то и публично известных) фреймворков и CMS просто берут в расчет только то, что между слэшами.

Далеко за примером ходить не надо, возьмем тот же Zend Framework. Внутри этого фреймворка реализована своя система маршрутизации, в зависимости от URL-адреса, по которому обращаются к сайту. То есть, изначально не требуется воротить сложные конструкции регулярок в htaccess и довести до белого каления с десяток форумов по веб-программированию. Все обращения к сайту перенаправляются на главный скрипт index.php, внутри которого подключаются уже классы и начинает работать программная маршрутизация, распарсивая URL на части и определяя тем самым, какие классы и методы в них надо вызывать.

Например, по-умолчанию (без подробностей, объясню попроще), адрес вида http://site.ru/user/register/form/ означает, что системе следует найти модуль «user», внутри которого содержится класс со специфическим именем «RegisterController» и у этого класса вызвать метод «form()».

ПОЛЕЗНО  Файловое кеширование DLE [снижаем нагрузку на MySQL]

Но беда в том, что для определения дальнейших действий в ход идут исключительно составные части адреса, без слэшей: user, register, form. И даже если мы уберем слэш в конце URL, то получим те же самые параметры, и результат работы сайта будет тот же самый. А адреса http://site.ru/user/register/form/ и http://site.ru/user/register/form — равноценными, по которым находятся дубли страниц.


Знакомые с PHP могут попробовать самостоятельно написать простой «интерпретатор» для URL. В результате чего увидят, что отслеживать слэш в конце URL не имеет смысла. Потому создатели CMS (редко) и фреймворков (практически всегда) отдают этот вопрос на решение разработчикам и вебмастерам конкретных сайтов.

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

Добавить завершающий слэш через .htaccess

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*[^/])$ $1/ [L,R=301]

Удалить завершающий слэш через .htaccess

<code>RewriteBase /
RewriteCond %{HTTP_HOST} (.*)
RewriteCond %{REQUEST_URI} /$ [NC]
RewriteRule ^(.*)(/)$ $1 [L,R=301]</code>

Вышеприведенные решения работают только для простых случаев (у меня, например). Если у вас в .htaccess уже полно всяких RewriteRule, то могут возникнуть конфликты между правилами. Тогда следует позвать специалиста и разбираться отдельно в каждом конкретном случае.

ПОЛЕЗНО  Сжатие (gzip) CSS и JS скриптом

Удалить слеш программно (PHP)

// Получаем URI для проверки
$uri = preg_replace("/\?.*/i",'', $_SERVER['REQUEST_URI']);

if (strlen($uri)>1) {// если не главная страница...
  if (rtrim($uri,'/')!=$uri) {
    header("HTTP/1.1 301 Moved Permanently");
    header('Location: http://'.$_SERVER['SERVER_NAME'].str_replace($uri, rtrim($uri,'/'), $_SERVER['REQUEST_URI']));
    exit();    
  }
}

Для Joomla надо учесть наличие админ-интерфейса по адресу /administrator/ — там лучше не редиректить, а то циклическое перенаправление получается (код вставлять в начало index.php):

$uri = preg_replace("/\?.*/i",'', $_SERVER['REQUEST_URI']);

if ((!strpos($uri, 'administrator'))  && (strlen($uri)>1)) {
  if (rtrim($uri,'/')!=$uri) {
    header("HTTP/1.1 301 Moved Permanently");
    header('Location: http://'.$_SERVER['SERVER_NAME'].str_replace($uri, rtrim($uri,'/'), $_SERVER['REQUEST_URI']));
    exit();    
  }
}

Добавить слеш программно (PHP)

// Получаем URI для проверки
$uri = preg_replace("/\?.*/i",'', $_SERVER['REQUEST_URI']);

if (strlen($uri)>1) {// если не главная страница...
  if (rtrim($uri,'/')."/"!=$uri) {
    header("HTTP/1.1 301 Moved Permanently");
    header('Location: http://'.$_SERVER['SERVER_NAME'].str_replace($uri, $uri.'/', $_SERVER['REQUEST_URI']));
    exit();    
  }
}

Для Joomla лучше не маяться и не ставить завершающий слеш (а, наоборот, убирать). Из-за того, что