JS Tower
Node.jsМодуль 4: HTTP и Express

Модуль http

Создание HTTP сервера на чистом Node.js

Цель урока

В этом уроке ты научишься:

  • Создавать HTTP сервер
  • Обрабатывать запросы и ответы
  • Понимать HTTP протокол

Создание сервера

const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Привет, мир!');
});

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

Объект Request (req)

const server = http.createServer((req, res) => {
  console.log('Метод:', req.method);        // GET, POST, PUT, DELETE
  console.log('URL:', req.url);             // /path?query=value
  console.log('Заголовки:', req.headers);   // { host: 'localhost', ... }
  
  res.end('OK');
});

Парсинг URL

const { URL } = require('url');

const server = http.createServer((req, res) => {
  const url = new URL(req.url, `http://${req.headers.host}`);
  
  console.log('Путь:', url.pathname);       // /users
  console.log('Query:', url.searchParams);  // URLSearchParams
  console.log('id:', url.searchParams.get('id'));
  
  res.end('OK');
});

Объект Response (res)

const server = http.createServer((req, res) => {
  // Статус и заголовки
  res.statusCode = 200;
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('X-Custom-Header', 'value');
  
  // Или одной командой
  res.writeHead(200, {
    'Content-Type': 'application/json',
    'X-Custom-Header': 'value'
  });
  
  // Тело ответа
  res.write('Часть 1');
  res.write('Часть 2');
  res.end('Конец');  // Завершает ответ
});

Маршрутизация

const server = http.createServer((req, res) => {
  const { method, url } = req;
  
  if (method === 'GET' && url === '/') {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end('<h1>Главная страница</h1>');
  } 
  else if (method === 'GET' && url === '/api/users') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify([{ id: 1, name: 'Иван' }]));
  }
  else if (method === 'POST' && url === '/api/users') {
    // Обработка POST
    let body = '';
    req.on('data', chunk => body += chunk);
    req.on('end', () => {
      const user = JSON.parse(body);
      res.writeHead(201, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ id: 2, ...user }));
    });
  }
  else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Не найдено');
  }
});

Получение тела запроса

function getBody(req) {
  return new Promise((resolve, reject) => {
    let body = '';
    req.on('data', chunk => body += chunk);
    req.on('end', () => {
      try {
        resolve(JSON.parse(body));
      } catch {
        resolve(body);
      }
    });
    req.on('error', reject);
  });
}

const server = http.createServer(async (req, res) => {
  if (req.method === 'POST') {
    const body = await getBody(req);
    console.log('Тело:', body);
  }
  res.end('OK');
});

Статические файлы

const http = require('http');
const fs = require('fs');
const path = require('path');

const MIME_TYPES = {
  '.html': 'text/html',
  '.css': 'text/css',
  '.js': 'text/javascript',
  '.json': 'application/json',
  '.png': 'image/png',
  '.jpg': 'image/jpeg'
};

const server = http.createServer((req, res) => {
  const filePath = path.join(__dirname, 'public', req.url === '/' ? 'index.html' : req.url);
  const ext = path.extname(filePath);
  const contentType = MIME_TYPES[ext] || 'application/octet-stream';
  
  fs.readFile(filePath, (err, data) => {
    if (err) {
      res.writeHead(404);
      res.end('Файл не найден');
      return;
    }
    
    res.writeHead(200, { 'Content-Type': contentType });
    res.end(data);
  });
});

HTTP клиент

const http = require('http');

// GET запрос
http.get('http://api.example.com/data', (res) => {
  let data = '';
  res.on('data', chunk => data += chunk);
  res.on('end', () => console.log(JSON.parse(data)));
});

// POST запрос
const options = {
  hostname: 'api.example.com',
  port: 80,
  path: '/users',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  }
};

const req = http.request(options, (res) => {
  let data = '';
  res.on('data', chunk => data += chunk);
  res.on('end', () => console.log(JSON.parse(data)));
});

req.write(JSON.stringify({ name: 'Иван' }));
req.end();

Рекомендация

Для HTTP клиента лучше использовать fetch (Node 18+) или библиотеку axios.


Практика

Задание 1: Простой сервер

Задача: Создай сервер, который отвечает JSON на /api/status.

Решение:

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/api/status') {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ status: 'ok', time: new Date() }));
  } else {
    res.writeHead(404);
    res.end('Not Found');
  }
});

server.listen(3000);

Проверь себя

  1. Как получить метод HTTP запроса?
  2. Как установить заголовок ответа?
  3. Как получить тело POST запроса?