Маршрутизация вручную

Разводим запросы по разным адресам своими руками — и понимаем, зачем нужен Express.

Что такое маршрутизация

Маршрутизация (routing) — это выбор, что ответить, в зависимости от пути (req.url) и метода (req.method) запроса. Запрос GET /users и POST /users — разные маршруты, и обрабатывать их нужно по-разному.

Ручной роутинг через if

На голом http маршруты разводят условиями. Проверяем метод и путь, формируем нужный ответ:

const http = require("http");

const server = http.createServer((req, res) => {
  res.setHeader("Content-Type", "text/plain; charset=utf-8");

  if (req.method === "GET" && req.url === "/") {
    res.writeHead(200);
    res.end("Главная");
  } else if (req.method === "GET" && req.url === "/about") {
    res.writeHead(200);
    res.end("О нас");
  } else {
    res.writeHead(404);
    res.end("Страница не найдена");
  }
});

server.listen(3000);

Работает, но обратите внимание: уже на трёх маршрутах появилась лесенка условий. На двадцати маршрутах с параметрами это станет нечитаемым.

Ответ 404 для неизвестных путей

Обязательно предусмотрите ветку «иначе» — иначе на неизвестный путь сервер не ответит ничего осмысленного. Статус 404 прямо говорит клиенту «такого адреса нет».

Маршрутизатор как таблица

Лесенку if можно заменить таблицей «маршрут → обработчик». Это уже ближе к тому, как устроен Express внутри. Идея — на чистом JS:

const routes = {
  "GET /": () => "Главная",
  "GET /about": () => "О нас",
  "GET /contact": () => "Контакты"
};

function route(method, url) {
  const key = `${method} ${url}`;
  const handler = routes[key];
  if (!handler) return "404 — не найдено";
  return handler();
}

console.log(route("GET", "/"));
console.log(route("GET", "/about"));
console.log(route("POST", "/"));

Вывод:

Главная
О нас
404 — не найдено

А параметры в пути?

Настоящая боль начинается с динамических путей вроде /users/42, где 42 — это id. На голом http такой путь приходится разбирать вручную: отрезать префикс, выделить число, проверить. Разбор — снова чистый JS:

function matchUser(url) {
  // ждём путь вида /users/<id>
  const match = url.match(/^\/users\/(\d+)$/);
  if (!match) return null;
  return { userId: Number(match[1]) };
}

console.log(matchUser("/users/42"));
console.log(matchUser("/users/abc"));
console.log(matchUser("/posts/1"));

Вывод:

{ userId: 42 }
null
null

Вывод: пора звать фреймворк

Ручная маршрутизация наглядно показывает, как работает сервер «под капотом». Но писать так каждый проект — мучение: параметры, парсинг тела, заголовки, ошибки. Ровно эти задачи берёт на себя Express — о нём в следующем уроке.

Итог

  • Маршрутизация — выбор ответа по req.method и req.url.
  • На голом http маршруты разводят условиями или таблицей «маршрут → обработчик».
  • Всегда добавляйте ветку 404 для неизвестных путей.
  • Динамические пути (/users/42) приходится разбирать вручную — это повод взять Express.
Проверьте себя
1. На основе чего выбирают, что ответить, при ручной маршрутизации?
AТолько req.url
Breq.method и req.url
CТолько req.headers
DСлучайным образом
2. Какой статус-код вернуть для неизвестного пути?
A200
B301
C404
D500
3. Почему ручная маршрутизация неудобна на больших проектах?
AОна не работает с GET
BРазрастается лесенка условий, тяжело разбирать параметры пути
CNode это запрещает
DОна медленнее на 50%
Поддержать проект