Обратная совместимость - это адекватная реакция программулины на устаревшие данные. К примеру, не секрет, что майкрософт офис 2007 прекрасно работает с документами от более ранних версий. То есть, офис 2007 имеет хорошую обратную совместимость.
Что касается сайтов, то под обратной совместимостью ссылок я понимаю примерно следующее: если какой-либо раздел был перемещён, то он должен работать и по старому адресу, и по новому.
Простое перемещение разделов сайта плохо сказывается на поисковиках и прямых ссылках на разделы.
Во-первых, поисковики. Они животные подневольные, телепатическими способностями не обладают, поэтому будут пытаться индексировать перемещённый раздел по старому адресу ещё долгое время после переезда раздела.
Во-вторых, пользователи. Было бы просто замечательно, если бы все перемещались по сайту, используя только родную навигацию. Но зачастую ссылки на полезную информацию распространяются в абсолютном виде сразу на целевой рездел. Поэтому, если такой раздел переедет и ссылка будет вести в никуда, то это плохо скажется и на поисковиках, и на репутации сайта.
Чтобы избежать подобных проблем, достаточно по старому адресу просто сообщить адрес переезда. Благо, HTTP имеет методы делать это культурно, используя редиректы.
Когда мой сайт только зарождался, то разделов было чуть больше, чем шиш да ещё чуть-чуть. Сайт состоял в основном из статей, которые располагались примерно так:
http://сайтец/articles/vm-server/ http://сайтец/articles/ImageCounter/ http://сайтец/articles/ImageList/ http://сайтец/articles/mysql-charsets/ |
Через некоторое время сайт подрос, статьи расплодились, и возникла необходимость расположить их уже по новым адресам:
http://сайтец/articles/os/vm/vm-server/ http://сайтец/articles/php/image-counter/ http://сайтец/articles/js/image-list/ http://сайтец/articles/mysql/mysql-charsets/ |
Поизучав документацию на нетленном http://apache.org, я понял, что всё, как в сказке. В смысле, есть три пути, и на всех грабли.
Первый путь решения проблемы с редиректами привёл к mod_alias
, директиве Redirect
.
Функционал сей конструкции сводится к следующему:
Redirect [type|code] addr1 add2 |
То есть, если начало запроса соответствует addr1
, то оно будет заменено на addr2
, а полученный адрес отправится клиенту с кодом возврата code
.
Всего доступно четыре типа редиректа:
permanent
, код 301indicating that the resource has moved permanently
)temp
, код 302temporary redirect status
). Этот тип редиректа используется по умолчаниюseeother
, код 303indicating that the resource has been replaced
)gone
, код 410indicating that the resource has been permanently removed
)В моём случае, Redirect
можно было бы использовать так
Файл - .htaccess | |
1 |
Redirect permanent /articles/vm-server/ /articles/os/vm/vm-server/ Redirect permanent /articles/ImageCounter/ /articles/php/image-counter/ ... |
Весьма просто и функционально. Однако, сделать какую-то дополнительную обработку запроса в данном случае не представляется возможным, а запрашиваемый путь должен точно соответствовать addr1
.
Впрочем, все недостатки Redirect
были устранены в RedirectMatch
.
В общем и целом, RedirectMatch
повторяет Redirect
, за тем исключением, что вместо addr1
можно использовать шаблон, а в addr2
значения, найденные в шаблоне.
Моя реализация выглядела таким образом:
Файл - .htaccess |
RedirectMatch permanent ^/articles/vm-server/?(.*)$ /articles/os/vm/vm-server/$1 RedirectMatch permanent ^/articles/ImageCounter/?(.*)$ /articles/php/image-counter/$1 RedirectMatch permanent ^/articles/ImageList/?(.*)$ /articles/js/image-list/$1 RedirectMatch permanent ^/articles/mysql-charsets/?(.*)$ /articles/mysql/mysql-charsets/$1 |
На домашнем сервере такой код работал на ура, но при заливке на хостинг произошла неприятность. Как только код оказался на рабочем сервере, где был настроен движок на mod_rewrite
, все редиректы перестали работать, как надо. Причиной стал тот самый mod_rewrite
, который каждый URL редиректа дополнительно модифицировал без зазрения совести.
Поизучав оную проблему в интернете, выяснилось, что mod_rewrite
не будет дружить с редиректами mod_alias
и лучше использовать что-то одно. Собственно выбора, как такового, и не пришлось делать, движок был важнее. От редиректов средствами mod_alias
пришлось отказаться.
Когда mod_alias
показал свою несостоятельность, пришлось делать редиректы средствами mod_rewrite
.
Чем плох сей метод?.. Всё ничего, да только сам модуль реврайта кривой и страшный как чудо-юдо болотное. Но об этом несколько позже.
Модуль mod_rewrite
позволяет менять URL-запроса в зависимости от ситуации и осуществлять внутренние или внешние переходы. Обработка ведётся при помощи правил RewriteRule
. Логика работы правил такая же, как и у RedirectMatch
, то есть, если найден шаблон, то выполняется правило. Но в отличие от RedirectMatch
один запрос может обрабатываться несколькими правилами RewriteRule
, включая подзапросы.
Моя реализация редиректов на mod_rewrite
на данный момент выглядит следующим образом:
Файл - .htaccess |
RewriteEngine On Options +FollowSymlinks ## Текущее расположение относительно корня сайта RewriteBase / ## Совместимость со старыми разделами ## Для работы требуется mod_rewrite # --------------------------------------------- # Статьи RewriteRule ^articles/vm-server/?(.*)$ /articles/os/vm/vm-server/$1 [R=301,L] RewriteRule ^articles/ImageCounter/?(.*)$ /articles/php/image-counter/$1 [R=301,L] RewriteRule ^articles/ImageList/?(.*)$ /articles/js/image-list/$1 [R=301,L] RewriteRule ^articles/mysql-charsets/?(.*)$ /articles/mysql/mysql-charsets/$1 [R=301,L] |
Флаги [R=301,L]
означают, что правило должно инициировать редирект с кодом 301, и правило является "последним" (L
- last). То есть, если шаблон будет найден и правило сработает, то все остальные правила должны исключаться.
Для проверки логики работы приведённого выше кода, я включил логи реврайта. Каково же было моё удивление, когда оказалось, что проверке подвергались шаблоны всех правил без исключений. То есть, ключ L
по-сути ни на что не влиял.
Дальнейшие эксперименты привели к следующему коду:
Файл - .htaccess |
RewriteEngine On RewriteRule index\.php$ index1.html [L] RewriteRule index1\.html$ index2.html [L] RewriteRule index2\.html$ index3.html [L] |
Моему удивлению не было предела! Мало того, что тестировались все три шаблона, дак ещё и срабатывали все три правила, если запрашивался index.php
.
Проверив таким способом апачи 1.3 и 2.2, я получил одинаковый результат, всегда возвращался index3.html
. Из чего пришлось сделать вывод, что mod_rewrite
, мягко говоря, не комильфо. Однако, за неимением лучшего, пришлось остаться на реврайте.