Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Маршруты вручную

Маршрут — правило «на такой метод и такой адрес отвечать так». Во фреймворках маршруты описывают одной строкой, а в чистом 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.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.