Маршруты вручную
Маршрут — правило «на такой метод и такой адрес отвечать так». Во фреймворках маршруты описывают одной строкой, а в чистом node:http их выбирают сами: смотрят на req.method и путь из req.url и решают, какой код выполнить.
Разбор адреса
req.url содержит путь вместе с параметрами: /posts?page=2. Встроенный класс URL разбирает его на части. Ему нужен базовый адрес, поэтому вторым аргументом передают любой хост:
const url = new URL('/posts?page=2', 'http://localhost');
console.log(url.pathname); // /posts
console.log(url.searchParams.get('page')); // 2В сервере вместо строки подставляют req.url.
Первые маршруты
Перепишите src/server.js: главная страница, список статей и ответ 404 для всего остального. Статьи берутся из модуля src/posts.js из урока про JSON-хранилище:
// src/server.js
import http from 'node:http';
import { loadPosts } from './posts.js';
function sendJson(res, status, data) {
res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify(data));
}
const server = http.createServer(async (req, res) => {
const { pathname } = new URL(req.url, 'http://localhost');
if (req.method === 'GET' && pathname === '/') {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Блог Анны');
} else if (req.method === 'GET' && pathname === '/posts') {
sendJson(res, 200, await loadPosts());
} else {
sendJson(res, 404, { error: 'Не найдено' });
}
});
server.listen(3000);http://localhost:3000/posts покажет массив статей в формате JSON, а http://localhost:3000/abc — объект с ошибкой и код 404. Функция-обработчик объявлена async, чтобы внутри работал await.
Параметр в адресе
Для адреса статьи /posts/2 номер достают регулярным выражением. Добавьте ветку перед блоком else:
// src/server.js
const match = pathname.match(/^\/posts\/(\d+)$/);
if (req.method === 'GET' && match) {
const post = await findPost(Number(match[1]));
if (post) sendJson(res, 200, post);
else sendJson(res, 404, { error: 'Статья не найдена' });
}Не забудьте импортировать findPost рядом с loadPosts. Выражение (\d+) захватывает цифры, они попадают в match[1] строкой, поэтому их превращают в число.
Параметры после знака вопроса
Номер страницы для списка берут из searchParams и задают значение по умолчанию:
const url = new URL('/posts?page=3', 'http://localhost');
const page = Number(url.searchParams.get('page') ?? 1);
const perPage = 5;
console.log(`Статьи с ${(page - 1) * perPage + 1} по ${page * perPage}`);Выведется «Статьи с 11 по 15». Нужный кусок массива затем вырезают методом slice().
Частая ошибка
Сравнивать req.url с адресом напрямую ненадёжно: /posts?page=2 и /posts/ не равны строке '/posts', и посетитель получит 404:
console.log('/posts?page=2' === '/posts'); // falseВсегда сравнивайте pathname, полученный через new URL(), а параметры читайте из searchParams.