Что такое роутинг в программировании
Перейти к содержимому

Что такое роутинг в программировании

  • автор:

Что такое роутинг в программировании

Router позволяет определить дочерние подмаршруты со своими обработчиками относительно некоторого главного маршрута. Например, определим следующее приложение:

const express = require("express"); const app = express(); app.use("/about", function (_, response) < response.send("О сайте"); >); app.use("/products/create",function (request, response) < response.send("Добавление товара"); >); app.use("/products/:id",function (request, response) < response.send(`Товар $`); >); app.use("/products/",function (request, response) < response.send("Список товаров"); >); app.use("/", function (request, response) < response.send("Главная страница"); >); app.listen(3000);

Здесь у нас есть пять маршрутов, которые обрабатываются различными обработчиками. Но три из этих маршрутов начинаются с «/products» и условно относятся к некоторому функционалу по работе с товарами (просмотр списка товаров, просмотр одного товара по id и добавление товара). Объект Router позволяет связать подобный функционал в одно целое и упростить управление им. Например, перепишем предыдущий пример с использованием объекта Router:

const express = require("express"); const app = express(); // определяем Router const productRouter = express.Router(); // определяем маршруты и их обработчики внутри роутера productRouter.use("/create", function(request, response)< response.send("Добавление товара"); >); productRouter.use("/:id", function(request, response)< response.send(`Товар $`); >); productRouter.use("/", function(request, response)< response.send("Список товаров"); >); // сопоставляем роутер с конечной точкой "/products" app.use("/products", productRouter); app.use("/about", function (request, response) < response.send("О сайте"); >); app.use("/", function (request, response) < response.send("Главная страница"); >); app.listen(3000);

Здесь определен объект productRouter, который обрабатывает все запросы по маршруту «/products». Это главный маршрут. Однако в рамках этого маршрута может быть подмаршрут «/» со своим обработчиком, а также подмаршруты «/:id» и «/create», которые также имеют свои обработчики.

Пишем современный маршрутизатор на JavaScript

Простые одностраничные приложения, основанные на React, Vue или чистом JavaScript, окружают нас повсюду. Хороший «одностраничник» предполагает соответствующий механизм маршрутизации.

Такие библиотеки, как «navigo» или «react-router», приносят большую пользу. Но как они работают? Необходимо ли нам импортировать всю библиотеку? Или достаточно какой-то части, скажем, 10%? В действительности, быстрый и полезный маршрутизатор можно легко написать самому, это займет немного времени, а программа будет состоять менее чем из 100 строчек кода.

Требования

Наш маршрутизатор должен быть:

  • написан на ES6+
  • совместим с историей и хешем
  • переиспользуемой библиотекой
  • маршрутизаторы (routes): список зарегистрированных маршрутизаторов
  • режим (mode): хеш или история
  • корневой элемент (root): корневой элемент приложения, если мы находимся в режиме использования истории
  • конструктор (constructor): основная функция для создания нового экземпляра маршрутизатора
class Router < routes = [] mode = null root = '/' constructor(options) < this.mode = window.history.pushState ? 'history' : 'hash' if (options.mode) this.mode = options.mode if (options.root) this.root = options.root >> export default Router 

Добавление и удаление маршрутизаторов

Добавление и удаление маршрутизаторов осуществляется через добавление и удаление элементов массива:

class Router < routes = [] mode = null root = '/' constructor(options) < this.mode = window.history.pushState ? 'history' : 'hash' if (options.mode) this.mode = options.mode if (options.root) this.root = options.root >add = (path, cb) => < this.routes.push(< path, cb >) return this > remove = path => < for (let i = 0; i < this.routes.length; i += 1) < if (this.routes[i].path === path) < this.routes.slice(i, 1) return this >> return this > flush = () => < this.routes = [] return this >> export default Router 

Получение текущего пути

Мы должны знать, где находимся в приложении в определенный момент времени.

Для этого нам потребуется обработка обоих режимов (истории и хеша). В первом случае, нам нужно удалить путь к корневому элементу из window.location, во втором — «#». Нам также необходима функция (clearSlash) для удаления всех маршрутизаторов (строки от начала до конца):

[. ] clearSlashes = path => path .toString() .replace(/\/$/, '') .replace(/^\//, '') getFragment = () => < let fragment = '' if (this.mode === 'history') < fragment = this.clearSlashes(decodeURI(window.location.pathname + window.location.search)) fragment = fragment.replace(/\?(.*)$/, '') fragment = this.root !== '/' ? fragment.replace(this.root, '') : fragment >else < const match = window.location.href.match(/#(.*)$/) fragment = match ? match[1] : '' >return this.clearSlashes(fragment) > > export default Router 

Навигация

Ок, у нас имеется API для добавления и удаления URL. Также у нас имеется возможность получать текущий адрес. Следующий шаг — навигация по маршрутизатору. Работаем со свойством «mode»:

[. ] getFragment = () => < let fragment = '' if (this.mode === 'history') < fragment = this.clearSlashes(decodeURI(window.location.pathname + window.location.search)) fragment = fragment.replace(/\?(.*)$/, '') fragment = this.root !== '/' ? fragment.replace(this.root, '') : fragment >else < const match = window.location.href.match(/#(.*)$/) fragment = match ? match[1] : '' >return this.clearSlashes(fragment) > navigate = (path = '') => < if (this.mode === 'history') < window.history.pushState(null, null, this.root + this.clearSlashes(path)) >else < window.location.href = `$#$` > return this > > export default Router 

Наблюдаем за изменениями

Теперь нам нужна логика для отслеживания изменений адреса как с помощью ссылки, так и с помощью созданного нами метода «navigate». Также нам необходимо обеспечить рендеринг правильной страницы при первом посещении. Мы могли бы использовать состояние приложения для регистрации изменений, однако в целях изучения сделаем это с помощью setInterval:

class Router < routes = []; mode = null; root = "/"; constructor(options) < this.mode = window.history.pushState ? "history" : "hash"; if (options.mode) this.mode = options.mode; if (options.root) this.root = options.root; this.listen(); >[. ] listen = () => < clearInterval(this.interval) this.interval = setInterval(this.interval, 50) >interval = () => < if (this.current === this.getFragment()) return this.current = this.getFragment() this.routes.some(route =>< const match = this.current.match(route.path) if (match) < match.shift() route.cb.apply(<>, match) return match > return false >) > > export default Router 

Заключение

Наша библиотека готова к использованию. Она состоит всего лишь из 84 строчек кода!

Код и пример использования на Github.

PHP-роутинг (Routing) для новичков

Роутинг — это маршрутизация: входящий URL разбирается специальным образом и по его результату выполняется определенный код. С роутингом напрямую связано понятие ЧПУ (человекопонятные урлы), которое позволяет исключить в адресах сложные параметры. Например вместо http://сайт/admin/new-page пришлось бы использовать http://сайт/admin.php?action=new-page

Любой входящий URL на сервере разбирается по единому стандарту. Полностью приводить документацию не буду (см. как пример функцию parse_url), важно лишь понять, что в адресе передается параметр path (путь на сервере), которого на сервере реально может не быть. Например в адресе http://сайт/admin каталога admin реально может не существовать.

То есть сервер, получив такой адрес, попытается найти каталог admin , но не найдя его, выдаст 404-страницу (not found).

Чтобы исключить такой вариант, серверу указывается, что для всех несуществующих каталогов и файлов, подключать php-файл (обычно index.php ).

Делается это в файле .htaccess с помощью Apache-модуля mod_rewrite. Вот довольно типовой вариант (MaxSite CMS):

RewriteCond % !-f RewriteCond % !-d RewriteRule ^(.*)$ /index.php/$1 [L,QSA]

Тут главная строчка с RewriteRule — именно она определяет шаблон входящего адреса (в примере это регулярное выражение) и что с ним делать. В данном примере будет подключен index.php с параметрами после слэша.

Строчка RewriteCond % !-f / -d указывает исключить из обработки реально существующие на сервере файлы и каталоги.

Похожий вариант, только чуть короче, от WordPress:

RewriteRule . /index.php [L]
RewriteRule ^(.*)$ /index.php?page=$1 [QSA]

Здесь принудительно добавляется query-параметр page.

Еще один распространенный вариант (пожалуй самый «типовой»):

RewriteRule (.*) index.php?$1 [QSA,L]

Все эти RewriteRule-правила делают простую вещь: как бы «преобразуют» входящий адрес в набор query-параметров. Например адрес http://сайт/admin превратится в http://сайт/index.php?admin

Посмотрите на полный код .htaccess :

 RewriteEngine on RewriteBase / RewriteCond % !-f RewriteCond % !-d RewriteRule (.*) /index.php?$1 [QSA,L] 

Если это какой-то подкаталог, то он указываетс в RewriteBase и как путь к php-файлу. Например каталог на сервере route :

 RewriteEngine on RewriteBase /route/ RewriteCond % !-f RewriteCond % !-d RewriteRule (.*) /route/index.php?$1 [QSA,L] 

Теперь, все адреса на сервере будут передаваться в файл index.php , а исходный адрес сохранится в виде query-параметра.

Если в index.php разместить

То мы можем увидеть query-параметры. В PHP за это отвечается суперглобальная переменная $_GET . Например для http://сайт/admin это будет admin , для http://сайт/admin/new-page — admin/new-page .

Таким образом, с помощью .htaccess происходит первая часть роутинга, где мы получаем готовый $_GET .

Кстати, насчет .htaccess WordPress. Он не создает $_GET , поэтому придется использовать $_SERVER[‘REQUEST_URI’] в который включается подкаталог. Работать с таким адресом уже будет сложней.

Второй этап роутинга выполняется полностью на PHP. Получив $_GET нужно решить что с ним делать. Например если адрес admin, подключить файл admin.php .

Существуют несколько принципиально разных подходов в организации роутинга. Наиболее популярный подход — это когда в адресе передаётся «действие», которое описывается через php-класс. Такой подход хорошо описан в CodeIgniter:

example.com/class/function/id/

Например пусть будет класс admin в нём метод edit, принимающий параметр $id.

example.com/admin/edit/23 class admin < function edit($id) < . >>

Это сильно утрированный пример, но он хорошо показывает соответствие адреса и php-класса.

Другой вариант похожий, но используется не классы, а функции.

example.com/admin/edit/23 function admin($params)

То есть функция — это первый сегмент, а остальные выступают уже как парметры. Встречается более «продвинутый» вариант.

example.com/admin function admin($params) < . >example.com/admin/edit/23 function admin_edit($params)

То есть имя функции строится по сегментам URL.

Третий, тоже распространенный вариант — адрес указывает на подключаемый файл.

example.com/admin $fn = 'pages/admin.php'; if (file_exists($fn)) reqiure($fn); else reqiure('pages/404.php');

Здесь все файлы хранятся в каталоге pages и подключаются только если реально существуют. Если файла нет, то подключается предопределенный 404-файл.

Если сайт представляет собой сложный проект, то как правило используют роутинг на основе php-классов. Так его проще поддерживать и развивать. Если же сайт состоит из небольшого количества страниц, то как правило используют подключаемые файлы, где один файл — это одна страница.

Строго говоря, роутинг «на классах» тоже использует «файловое» подключение. Вначале подключается файл с кодом класса, а уже после этого выполняется сам класс.

В задачу роутинга входит не только необходимое «действие», но и валидация входящего адреса и его лексический разбор.

Адреса могут строиться по шаблону. Например какой-то адрес должен содержать только номер, а не текст (например example.com/admin/edit/23 , но не example.com/admin/edit/hello ). Или адрес может быть неизменным, но обработчик будет меняться от вида запроса GET или POST. В одном случае нужно подключить одну функцию/файл, в другом — другой. Бывают и более сложные задачи, все их перечислять нет смысла, поэтому появились разного рода php-библиотеки для организации роутинга.

Свой «велосипед» не изобретал только ленивый, но я отмечу довольно известный FastRoute, который вобрал в себя наиболее типичные решения.

В первую очередь это использование регулярных выражений при задании правил, например:

$r->addRoute('GET', '/user/', 'handler1');

Примерно такой же подход используется и в роутинге CodeIgniter.

products/shirts/123 $route['products/([a-z]+)/(d+)'] = "$1/id_$2";

То есть входящий адрес должен соответствовать шаблону и только в этом случае он «сработает».

В FastRoute реализована поддержка POST и GET-запросов. Такая возможность интересна, хотя на больших проектах такие вещи лучше делать на уровне самого «действия». Но это уже тонкости. Про эту библиотеку я упоминаю в первую очередь из-за того, что она достаточно популярна и уже используется в нескольких интересных проектах: Slim и Lumen.

Для небольших проектов, конечно же, FastRoute будет избыточна, поэтому можно ограничиться вариантом попроще, да и мозги потренировать. 🙂

ТЗ. Пусть роутинг будет обрабатывать адреса вида http://сайт/blog/contact/map , по которому будет подключен файл content/blog/contact/map/index.php , где каталог content — это общее хранилище всех страниц сайта, а index.php — обязательный файл с кодом страницы. Роутинг должен проверять реальный файл и если его нет, то подключать 404-страницу. Если никаких параметров нет, то это home-страница. Пусть они будут предопределены.

Решение. По сути задача сводится к преобразованию входящего адреса в путь на сервере. У нас есть массив $_GET , где первый ключ и есть входящий URL. Дальше формируем путь к файлу и если он есть, то подключаем. Если нет, то подключаем 404-страницу.

Весь код в 2 строчки:

Это простой роутинг для простых проектов. Достаточно создать в content каталог, как он станет доступен по одноименному адресу.

Как настроить роутинг в веб-приложении

Освойте основы настройки роутинга в веб-приложении с этим пошаговым руководством, подходящим для новичков в веб-разработке.

Web application routing example

Алексей Кодов
Автор статьи
1 июня 2023 в 9:02

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

Шаг 1: Выберите подходящий роутер

Первым делом нужно выбрать подходящий роутер для вашего веб-приложения. Разные фреймворки предоставляют разные инструменты для роутинга. Например, для React вы можете использовать react-router , а для Angular — @angular/router . Поэтому выберите роутер в зависимости от используемого вами фреймворка.

Шаг 2: Создайте компоненты страниц

Теперь создайте компоненты, которые будут использоваться в качестве страниц в вашем веб-приложении. Например, для простого веб-приложения можно создать следующие компоненты:

  • Главная страница (Home)
  • Страница проектов (Projects)
  • Страница контактов (Contacts)

Шаг 3: Установите роутер

Следующим шагом будет установка выбранного роутера с помощью команды установки пакета, например:

npm install react-router-dom 
npm install @angular/router 

Шаг 4: Настройте роуты

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

Вот пример настройки роутов для React с использованием react-router-dom :

import < BrowserRouter as Router, Route, Switch >from 'react-router-dom'; import Home from './components/Home'; import Projects from './components/Projects'; import Contacts from './components/Contacts'; function App() < return ( <Router> <Switch> <Route path="/" exact component=/> <Route path="/projects" component= /> <Route path="/contacts" component= /> </Switch> </Router> ); > export default App;

Python-разработчик: новая работа через 9 месяцев
Получится, даже если у вас нет опыта в IT

Шаг 5: Добавьте навигацию

После настройки роутов добавьте ссылки на страницы в вашем веб-приложении, чтобы пользователи могли переходить между ними. Вот пример добавления навигации для React с использованием react-router-dom :

import < NavLink >from 'react-router-dom'; function Navigation() < return ( <nav> <NavLink to="/" exact activeClassName="active"> Home </NavLink> <NavLink to="/projects" activeClassName="active"> Projects </NavLink> <NavLink to="/contacts" activeClassName="active"> Contacts </NavLink> </nav> ); >export default Navigation;

Теперь вы знаете основы настройки роутинга в веб-приложении. Не забывайте экспериментировать и углубляться в документацию выбранного роутера, чтобы узнать больше о его возможностях и оптимизации. Удачи! ��

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *