JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Обработка входящих запросов, отправка ответов

Обработка входящих запросов, отправка ответов

Модуль 4: Node.js, Next.js и Angular
4 уровень , 2 лекция
Открыта

1. Как работает сервер и что такое запрос/ответ

Представьте: ваш сервер — это работник почты. Клиент (браузер, Postman или другой сервер) приносит ему письмо (HTTP-запрос), а ваша задача — прочитать его, понять, что от вас хотят, и отправить ответ.

В Node.js за это отвечает функция-обработчик, которую вы передаёте в http.createServer. Она вызывается каждый раз, когда кто-то стучится к вашему серверу.

const http = require('http');

const server = http.createServer((req, res) => {
  // Здесь вы обрабатываете запрос и отправляете ответ
});

server.listen(3000);

Здесь req — объект запроса (request), а res — объект ответа (response).

2. Объект запроса (req): что в нём есть

Когда клиент делает запрос, Node.js создаёт объект req с кучей полезной информации:

  • req.method — HTTP-метод (например, 'GET', 'POST', 'PUT', 'DELETE')
  • req.url — путь запроса (например, '/', '/about', '/api/data?sort=desc')
  • req.headers — объект с заголовками запроса (например, User-Agent, Accept, Content-Type)
  • Поток данных тела запроса для методов вроде POST/PUT

Пример: вы заходите в браузере по адресу http://localhost:3000/hello?name=Vasya

const http = require('http');

const server = http.createServer((req, res) => {
  console.log('Method:', req.method); // GET
  console.log('URL:', req.url);       // /hello?name=Vasya
  console.log('Headers:', req.headers);
  // ...
});

server.listen(3000);

Парсим путь и query-параметры

Для разбора URL используйте встроенный класс URL:

const url = new URL(req.url, `http://${req.headers.host}`);
console.log(url.pathname); // /hello
console.log(url.searchParams.get('name')); // Vasya

Лайфхак: Не забывайте второй аргумент в new URL() — без него Node.js не сможет распознать относительный путь.

3. Объект ответа (res): как отправлять ответ клиенту

Объект res — это как конверт, в который вы кладёте свой ответ.

Самое главное:

  • res.statusCode — HTTP-статус (по умолчанию 200)
  • res.setHeader(name, value) — добавить или изменить заголовок
  • res.write(data) — отправить часть данных клиенту (можно вызывать несколько раз)
  • res.end([data]) — завершить ответ (и опционально отправить последнюю порцию данных)

Простейший ответ: текст

const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200; // Можно не указывать, 200 — по умолчанию
  res.setHeader('Content-Type', 'text/plain; charset=utf-8');
  res.end('Привет, мир!');
});

server.listen(3000);

Откройте в браузере http://localhost:3000 — увидите "Привет, мир!".

Отправка HTML-страницы

Если вы хотите отправить HTML, просто поменяйте Content-Type:

res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end('<h1>Заголовок</h1><p>Это HTML-страница</p>');

В браузере это отобразится как настоящая страница, а не просто текст.

Отправка JSON-ответа (например, для API)

Когда вы пишете API, обычно нужно отправлять данные в формате JSON. Для этого:

  1. Установите правильный заголовок
  2. Преобразуйте объект в строку с помощью JSON.stringify
const data = { name: 'Vasya', age: 25 };

res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.end(JSON.stringify(data));

Памятка: Не забудьте про JSON.stringify! Если отправите объект напрямую, будет ошибка.

4. Пример: сервер, который отвечает по разным адресам

Давайте напишем мини-сервер, который по разным путям отвечает по-разному. Это основа для будущей маршрутизации.

const http = require('http');

const server = http.createServer((req, res) => {
  const url = new URL(req.url, `http://${req.headers.host}`);

  if (url.pathname === '/') {
    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.end('<h2>Главная страница</h2>');
  } else if (url.pathname === '/about') {
    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.end('<h2>О сайте</h2><p>Этот сервер написан на Node.js!</p>');
  } else if (url.pathname === '/api/user') {
    res.setHeader('Content-Type', 'application/json; charset=utf-8');
    res.end(JSON.stringify({ name: 'Vasya', age: 25 }));
  } else {
    res.statusCode = 404;
    res.setHeader('Content-Type', 'text/plain; charset=utf-8');
    res.end('Страница не найдена');
  }
});

server.listen(3000, () => {
  console.log('Сервер запущен на http://localhost:3000');
});

Теперь попробуйте открыть разные адреса в браузере:

  • / — главная страница
  • /about — страница "О сайте"
  • /api/user — JSON с данными пользователя
  • что-то другое — 404

5. Чтение тела запроса (POST/PUT)

Для методов вроде POST или PUT клиенты могут отправлять данные в теле запроса. В Node.js тело запроса — это поток данных, который нужно "собирать" вручную (если не используете фреймворки типа Express).

Пример: сервер, который принимает JSON в POST-запросе и возвращает его обратно.

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.method === 'POST' && req.url === '/echo') {
    let body = '';

    // Слушаем событие 'data' — приходит кусочек данных
    req.on('data', chunk => {
      body += chunk;
    });

    // Когда все данные получены
    req.on('end', () => {
      try {
        const data = JSON.parse(body);
        res.setHeader('Content-Type', 'application/json; charset=utf-8');
        res.end(JSON.stringify({ received: data }));
      } catch (err) {
        res.statusCode = 400;
        res.end('Некорректный JSON');
      }
    });
  } else {
    res.statusCode = 404;
    res.end('Страница не найдена');
  }
});

server.listen(3000, () => {
  console.log('Сервер запущен на http://localhost:3000');
});

Проверьте этот сервер через Postman или cURL:

curl -X POST http://localhost:3000/echo -H "Content-Type: application/json" -d '{"msg": "Hello"}'

6. Практика: продолжаем развивать наше приложение

Давайте расширим наш сервер из предыдущих примеров. Например, добавим простой API для списка задач (todo). Пока что список задач будем хранить в памяти — как массив.

const http = require('http');

let todos = [
  { id: 1, text: 'Купить хлеб', done: false },
  { id: 2, text: 'Позвонить маме', done: true }
];

const server = http.createServer((req, res) => {
  const url = new URL(req.url, `http://${req.headers.host}`);

  // Получить список задач
  if (req.method === 'GET' && url.pathname === '/api/todos') {
    res.setHeader('Content-Type', 'application/json; charset=utf-8');
    res.end(JSON.stringify(todos));
    return;
  }

  // Добавить задачу
  if (req.method === 'POST' && url.pathname === '/api/todos') {
    let body = '';
    req.on('data', chunk => body += chunk);
    req.on('end', () => {
      try {
        const data = JSON.parse(body);
        const newTodo = {
          id: todos.length + 1,
          text: data.text || '',
          done: false
        };
        todos.push(newTodo);
        res.statusCode = 201; // Created
        res.setHeader('Content-Type', 'application/json; charset=utf-8');
        res.end(JSON.stringify(newTodo));
      } catch (e) {
        res.statusCode = 400;
        res.end('Некорректный JSON');
      }
    });
    return;
  }

  // Если путь не найден
  res.statusCode = 404;
  res.end('Не найдено');
});

server.listen(3000, () => {
  console.log('Сервер задач запущен на http://localhost:3000');
});

Теперь вы можете:

Получить список задач:
GET http://localhost:3000/api/todos

Добавить задачу:
POST http://localhost:3000/api/todos с телом { "text": "Сделать домашку" }

7. Типичные ошибки при обработке запросов и отправке ответов

Ошибка №1: Не завершён ответ.
Если забыть вызвать res.end(), клиент будет ждать ответа вечно (или до таймаута). Даже если вы отправили все данные через res.write(), обязательно завершайте ответ.

Ошибка №2: Неправильный Content-Type.
Если отправляете JSON, но забыли поставить заголовок Content-Type: application/json, браузер или другой клиент может не понять ваш ответ. Для HTML тоже важно указывать text/html.

Ошибка №3: Парсинг тела запроса без проверки метода.
Часто новички пытаются читать тело запроса для любого метода, даже для GET (у которого обычно тела нет). Читайте тело только для нужных методов (POST, PUT и т.п.).

Ошибка №4: Необработанные ошибки при парсинге JSON.
Если клиент отправил некорректный JSON, ваш сервер может "упасть". Всегда используйте try/catch при работе с JSON.parse.

Ошибка №5: Не учитывается асинхронность.
В Node.js всё, что связано с событиями (on('data'), on('end')), выполняется асинхронно. Не пытайтесь отправить ответ до завершения получения всех данных.

1
Задача
Модуль 4: Node.js, Next.js и Angular, 4 уровень, 2 лекция
Недоступна
Ответ в формате JSON для определенного маршрута
Ответ в формате JSON для определенного маршрута
1
Задача
Модуль 4: Node.js, Next.js и Angular, 4 уровень, 2 лекция
Недоступна
POST-запрос с обработкой тела и возвратом полученных данных
POST-запрос с обработкой тела и возвратом полученных данных
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ