1. Минимальный сервер
Мы напишем с нуля простой HTTP-сервер на Node.js, который:
- Принимает входящие запросы на разные адреса (роуты)
- Отвечает разным текстом в зависимости от URL
- Корректно устанавливает HTTP-заголовки и коды ответа
- Умеет отдавать простой HTML и JSON
- Не падает, если пользователь попросил несуществующую страницу
Всё это — база, на которой строятся любые сайты и API. И, поверьте, даже такие простые серверы иногда используются в продакшене (например, для моков, тестов, или микросервисов).
Что мы будем делать?
Давайте начнём с самого минималистичного сервера. Для этого нам понадобится модуль http, который уже встроен в Node.js, так что ничего дополнительно устанавливать не нужно.
Создайте файл server.js и напишите следующее:
// Импортируем модуль http
const http = require('http');
// Создаём сервер
const server = http.createServer((req, res) => {
// req — объект запроса (что пришло от клиента)
// res — объект ответа (что мы отправим клиенту)
res.statusCode = 200; // Устанавливаем HTTP-статус 200 (ОК)
res.setHeader('Content-Type', 'text/plain'); // Говорим браузеру, что это обычный текст
res.end('Привет, мир! Мой первый сервер на Node.js.');
});
// Запускаем сервер на порту 3000
server.listen(3000, () => {
console.log('Сервер запущен на http://localhost:3000');
});
Запустите этот файл командой:
node server.js
Откройте браузер и перейдите по адресу http://localhost:3000 — вы увидите заветное "Привет, мир!".
Как это работает?
- http.createServer создаёт сервер и принимает функцию-обработчик, которая вызывается при каждом запросе.
- Внутри обработчика мы формируем ответ: устанавливаем статус, заголовки, и отправляем данные методом res.end().
- server.listen() запускает сервер и начинает слушать указанный порт.
2. Разбираем код по частям
Импорт модуля http
const http = require('http');
Node.js использует систему модулей CommonJS, поэтому для подключения стандартного модуля используем require. Модуль http даёт всё необходимое для работы с HTTP-протоколом.
Создание сервера
const server = http.createServer((req, res) => {
// ...
});
Здесь мы создаём сервер и сразу передаём функцию-обработчик. Эта функция будет вызвана каждый раз, когда к серверу кто-то обратится (например, откроет страницу в браузере или отправит запрос с Postman).
Объекты req и res
- req (request) — содержит всю информацию о запросе: адрес, метод (GET, POST и т.д.), заголовки, тело запроса.
- res (response) — через него мы формируем и отправляем ответ клиенту: можем задать статус, заголовки, тело ответа.
Установка статуса и заголовков
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
- statusCode — HTTP-статус (200 — всё хорошо, 404 — не найдено, 500 — ошибка сервера и т.д.)
- setHeader — позволяет указать заголовки. В данном случае мы говорим браузеру, что отправляем обычный текст.
Отправка ответа
res.end('Привет, мир!');
Метод end завершает формирование ответа и отправляет его клиенту. Всё, что вы передадите в end, попадёт в браузер (или другой клиент).
3. Добавляем маршрутизацию (роутинг)
Один из самых частых вопросов: как сделать так, чтобы сервер отвечал разным текстом на разные адреса? Например, на / отдавал приветствие, а на /about — рассказывал о себе.
Для этого нам нужно посмотреть на свойство req.url:
const server = http.createServer((req, res) => {
// req.url — строка с адресом запроса, например "/about"
if (req.url === '/') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end('<h1>Главная страница</h1><p>Добро пожаловать на мой сервер!</p>');
} else if (req.url === '/about') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end('<h1>О сервере</h1><p>Этот сервер написан на Node.js.</p>');
} else if (req.url === '/api') {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
// Отправим JSON как строку
res.end(JSON.stringify({ message: 'Это API', status: 'ok' }));
} else {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/html');
res.end('<h1>404 - Не найдено</h1><p>Такой страницы нет :(</p>');
}
});
Теперь сервер умеет:
- Отвечать разным HTML на / и /about
- Отдавать JSON на /api
- Отдавать ошибку 404 на любые другие адреса
4. Пример полноценного сервера (пошагово)
Давайте напишем весь код сервера с комментариями:
const http = require('http');
// 1. Создаём сервер
const server = http.createServer((req, res) => {
// 2. Логируем запросы для наглядности
console.log(`${req.method} ${req.url}`);
// 3. Простейший роутинг
if (req.url === '/' && req.method === 'GET') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(`
<h1>Главная страница</h1>
<p>Добро пожаловать! <a href="/about">О сервере</a> | <a href="/api">API</a></p>
`);
} else if (req.url === '/about' && req.method === 'GET') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(`
<h1>О сервере</h1>
<p>Этот сервер написан на Node.js.<br>
<a href="/">На главную</a></p>
`);
} else if (req.url === '/api' && req.method === 'GET') {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
// Отправим JSON как строку
res.end(JSON.stringify({
success: true,
message: 'Привет из API!',
time: new Date().toISOString()
}));
} else {
// 4. Если адрес не найден — 404
res.statusCode = 404;
res.setHeader('Content-Type', 'text/html');
res.end(`
<h1>404 — Не найдено</h1>
<p>Такой страницы нет! <a href="/">На главную</a></p>
`);
}
});
// 5. Запускаем сервер на порту 3000
const PORT = 3000;
server.listen(PORT, () => {
console.log(`Сервер запущен на http://localhost:${PORT}`);
});
Что происходит по шагам?
- Импортируем модуль http.
- Создаём сервер с обработчиком запросов.
- Логируем каждый запрос (для отладки и понимания, что происходит).
- Проверяем URL и метод запроса — отвечаем разным содержимым.
- Для неизвестных адресов возвращаем ошибку 404.
- Запускаем сервер на порту 3000.
5. Как протестировать сервер
Откройте браузер и попробуйте адреса:
- http://localhost:3000/
- http://localhost:3000/about
- http://localhost:3000/api
- http://localhost:3000/somewhere (должна быть 404)
Можно использовать curl или Postman для проверки (особенно удобно для API):
curl http://localhost:3000/api
В консоли вы увидите логи всех входящих запросов.
6. Добавляем обработку POST-запросов (чуть сложнее)
Давайте научим сервер принимать данные, отправленные методом POST (например, с формы или из API-клиента). Для этого нам нужно "собирать" тело запроса вручную — Node.js не делает этого автоматически (в отличие от Express).
Добавим новый роут /echo, который повторяет (эхом) всё, что вы ему отправите:
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/echo' && req.method === 'POST') {
let body = '';
// Слушаем поступающие данные (частями)
req.on('data', chunk => {
body += chunk;
});
// Когда все данные получены
req.on('end', () => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({
received: body
}));
});
} else {
res.statusCode = 404;
res.end('Not found');
}
});
server.listen(3000, () => {
console.log('Сервер на порту 3000');
});
Теперь можно отправить POST-запрос через curl:
curl -X POST -d "hello=world" http://localhost:3000/echo
Ответ будет:
{"received":"hello=world"}
Зачем это всё?
- Вы учитесь работать с HTTP-протоколом "на низком уровне" — это мощное знание, пусть даже большинство разработчиков пользуются фреймворками типа Express.
- Понимаете, как обрабатываются разные методы запросов (GET, POST).
- Видите, как сервер "собирает" тело запроса по частям (streaming!), что важно для больших данных.
7. Типичные ошибки при написании простого сервера
Ошибка №1: забыли вызвать res.end()
Если не вызвать res.end(), браузер будет ждать ответа вечно — и вы увидите "вечную загрузку". Всегда завершайте ответ!
Ошибка №2: неправильный Content-Type
Если отправляете JSON, но забыли поставить Content-Type: application/json, браузер и клиенты могут не распознать ответ как JSON. Аналогично с HTML.
Ошибка №3: не проверяете метод запроса
Часто пишут только проверку URL, но забывают про метод (GET, POST и др.). В результате сервер может принять не тот тип запроса, что ожидалось.
Ошибка №4: не обрабатываете неизвестные адреса
Если не добавить блок для 404, сервер просто ничего не ответит или вернёт неинформативную ошибку.
Ошибка №5: не логируете ошибки
Если в обработчике возникла ошибка, а вы не вывели её в консоль, будет сложно понять, что пошло не так. Логируйте всё, что кажется подозрительным!
Ошибка №6: забыли перезапустить сервер после изменения кода
Node.js не перезапускает сервер автоматически (если не используете nodemon). После изменений обязательно останавливайте сервер и запускайте снова.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ