Роутер, как компонент веб-системы. Часть 1.

Я продолжаю разбирать разные компоненты CMS. Предыдущие заметки по теме:

Любая страница сайта доступна по какому-то адресу (URL). Бывает, конечно, что у одной и то же страницы несколько адресов. Или наоборот, при какой-то динамической погрузке контента, в итоге пользователь по одному и тому же адресу увидит разные страницы (Что является грубой ошибкой, но ою этом как-нибудь потом). Но в целом какое-то соответствие адреса и страницы есть всегда.

К радости начинающих и ленивых разработчиков, это соответствие уже работает на стороне web-сервера. Сначала, он с помощью механизма Виртуальных Хостов определяет корневую директорию сайта и сам ищет в ней фаил index, который и становится главной страницей. Потом, каждой папке dir ставит в соответствие адрес mysite.ru/dir/. Для простых сайтов без сложной внутренней архитектуры этого вполне достаточно.

Что же не так?

Но при построении CMS возникает ряд сложностей с такой системой:

  1. Хочется из административной панели управлять URL-ами. А это значит, надо дать возможность оттуда создавать и удалять папки. Это не безопасно давать администратору сайта такие серьезные права на сервере. С ними он может снести весь сайт. А право управления URL фактически приравняется к праву администратора сервера.
  2. Перенос кода из одних папок в другие сильно осложнит разработчикам жизнь. Такая неразбериха противоречит идеям контроля версий кода. Кроме того, усложняет задание относительных путей внутри системы.
  3. Код разбросанный по разным папкам по принципу отношения к разделам, прямо скажем, очень плохое архитектурное решение. Нам важно минимизировать дублирование кода и упростить разработчикам поиск места «где считается вот-такая-вот циферка». И та и другая задача решены в этом случае крайне плохо.
  4. URL должен быть удобен для пользователя и понятен поисковым роботам, а внутренняя система директорий должна быть удобна и понятна разработчикам. Нет никакого смысла усложнять жизнь одним, в угоду других. Этот пункт частично пересекается с предыдущими, но думаю, что его стоит выделить.

Все эти сложности и, возможно, еще какие-то заставили разработчиков искать выход. Я наблюдал в разных системах несколько вариантов таких выходов. Принципиально можно выделить два подхода.

В каждой папке подключаем ядро

Оставляем маршрутизацию на совесть web сервера, но отказываемся от кода внутри каждого раздела. Все, что мы делаем — это запоминаем что это за раздел (например записываем его ID) и дальше подключаем «ядро системы», которое уже обрабатывает запрос, готовит контент и т.д.
В этом случае внутри папки about будет примерно такой код:

$section = ‘22’;
include(‘/includes/core.php’);

А вся остальная система уже разворачивается из core.php.

Плюсы такого подхода в том, что он работает по умолчанию на любом web-сервере. То есть у нас не будет проблем при переезде с Apache на Nginx. Так же не будет проблем при переезде на хостинг, где нам запретили что-либо менять в настройках web-сервера, в том числе с помощью файла .htaccess и ему подобных.

Минусы в том, что пользователь все-же из административной панели управляет созданием и удалением папок. Это может привести к трудноуловимым ошибкам. Например, если администратор сайта создаст раздел lib, а у нас есть такая папка и она содержит важные для нас библиотеки, то либо он её удалит и прекратит работать вообще все, либо не сможет создать раздел и опечалится.

Единая точка входа

Более распространенный в крупных системах вариант — это единая точка входа. Тут основная идея простая. Что бы не запросил пользователь мы должны всегда отправить его в один и тот же фаил, где уже разобрать его запрос и решить какой контент стоит отдать. Обычно при таком подходе вариант по умолчанию все равно остается и помогает подключать скрипты картинки и т.д. Но для основных адресов сайта паки не создаются. Вместо этого мы так настраиваем наш web-сервер, что бы при невозможности найти папку мы всех отправляли в единый фаил. А в нем уже решаем валидный это адрес для нашей системы или надо отдать какую-нибудь ошибку.
Вот пример простого .htaccess для такого подхода:

RewriteEngine on

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^.*$ /core.php [NC,L]

Тут написано, что если ни фаил ни дириктория не найдены, то отправлять все в core.php.

Главный плюс такого подхода — бОльшая гибкость. Ну а минус — сложности при переносе на дешевые хостинги.
Отдельно хочу отметить, что этот подход очень хорошо сделан в Yii фраемворке. Все файлы, которые нужно находить «встроенной» навигацией находятся в папке public, а все «внутренности» в отдельной папке protected. Такое распредление позволяет достаточно безопасно настроить права доступа.

#После точки входа
В обоих подходах всегда есть общая точка входа. И у же в ней идет формирование того, что мы отдадим пользователю. Как правило эта точка входа построена в два этапа. В первом этапе подключаются и инициализируются срикпты, которые должны работать на сайте всегда, не зависимо от того, куда хотел попасть пользователь. Это, например, подключение к базе данных.
А второй этап, как правило, зависит от того, что запросил пользователь. Конечно, можно прописать в ядре какой-то гигантский оператор switch и при добавлении каждого нового функционала дописывать к нему опции. Но это подход человека, который не слышал об архитектуре приложении. Более же правильный путь — создать набор модулей. И по надобности подключать тот или иной модуль. Именно так устроены большинство CMS и фраемворков.
В таком случае нам понадобится блок в коде, который принимает запрос и решает какой или какие модули нужно подключить. Именно этот блок и называют Роутером или по-русски Маршрутизатором.

Уф. Большое получилось вступление. Пожалуй, остановлюсь тут и продолжу во второй части.

Share
Send
Pin
Popular