JS: HTTP Server
2026-02-26 23:01 Diff

В веб-разработке, процесс, который отвечает за определение обработчика для конкретной запрашиваемой страницы, называется маршрутизация. Чаще говорят "роутинг". Посмотрим на пример:

https://ru.hexlet.io/code_reviews/4172 https://ru.hexlet.io/courses/programming-basics https://ru.hexlet.io/account/profile/edit

Каждый адрес из примера выше представляет собой конкретный маршрут (роут). Причём их можно разделить по типу: статические и динамические.

Статические маршруты

Характеризуются тем, что адрес совпадает с самим маршрутом. Например, account/profile/edit. Несмотря на то, что адрес один, у разных пользователей он будет отображать разные данные, зависящие от того, кто сейчас авторизован.

Динамические маршруты

А что, если у нас есть адреса, которые обозначают одно и тоже, но содержат параметр. Типичный пример /users/5. Без особого труда можно понять, что по этой ссылке мы получим информацию о пользователе с номером 5. Но тогда возникает вопрос: если у нас в базе тысячи пользователей, нам придётся определять тысячи маршрутов?

К счастью, нет, здесь нам на помощь приходят регулярные выражения. Создаётся один маршрут, который выглядит примерно так: ^/users/(\w+). А дальше нужно просто сопоставить это регулярное выражение со строкой запроса. Другими словами, мы определили один единственный маршрут, который покрывает подобные ссылки:

/users/4 /users/1234 /users/3 /users/robocop

После этого момента становится понятно, что процесс роутинга – это чуть сложнее, чем просто большой if/switch. В будущем мы начнём работать с фреймворками, в которых роутинг является одной из основных подсистем. Это справедливо для всех web-фреймворков на всех языках.

Как правило, фреймворки предоставляют более высокоуровневый способ работы с роутами. То есть, вы пишете не сырые регулярные выражения, а строки с плейсхолдерами: /users/:id. Эти строки внутри заменяются на регулярные выражения и сопоставляются с запрашиваемыми адресами. Плейсхолдеры, в подавляющем большинстве фреймворков, заменяются на группу \w+. Эта группа не включает в себя / и требует обязательного наличия хотя бы одного символа. Это значит, что следующие маршруты не подходят под маршрут /users/:id:

/users /users/4/photos /users/my/d

В нашем сервере мы реализовали следующий способ работы роутера. Отдельно описывается объект, содержащий правила роутинга (как ключи) и обработчики маршрутов (как значения):

Обратите внимание на важную деталь. Метод http тоже является частью роутинга. Для GET- и POST-запросов на /users будет использоваться два роута. Это связано с большим количеством причин, одной из которых является семантика http. А вот параметры запроса (например, /users?name=Tirion) не являются частью процесса маршрутизации (при таком роутинге, как выше). Они уже используются внутри обработчиков на ваше усмотрение.

Также имеет значение порядок, в котором заданы маршруты. Поэтому первыми должны идти статические и наиболее конкретизированные маршруты, а в конце более общие. Это правило справедливо в том случае, если есть пересечения.

Ещё остаётся работа с ошибками, такими как "страница не найдена". Здесь уже возможны варианты. Некоторые фреймворки обрабатывают эту ситуацию отдельно, проверяя, что ни один маршрут не совпал с запрошенным адресом, и выполняя специальный обработчик для этой ситуации. В других достаточно определить в самом конце маршрут *, в который попадет всё, что не попало в другие места. И из обработчика этого роута можно делать всё, что нужно для правильного отображения ошибки.

Пример простого способа обрабатывать маршруты:

Соглашения

В web-разработке существует понятие CRUD (в русскоязычной среде говорят "круд"), которое расшифровывается как CREATE, READ, UPDATE, DELETE. И самое простое и базовое, что делают разработчики — это круды. Например, любой административный интерфейс (админка сайта) — это большой набор разных крудов для всевозможных сущностей: круд постов в блог, круд товаров и так далее.

Существуют соглашения о том, как грамотно делать круды с точки зрения маршрутизации. Они включают в себя особенности семантики http.

GET /users # список POST /users # создание GET /users/10 # просмотр PATCH /users/10 # обновление DELETE /users/10 # удаление GET /users/10/photos # список фотографий