HTTP-статусы: 1xx, 2xx, 3xx, 4xx, 5xx

HTTP-статус-коды — трёхзначные числа в ответе сервера, информирующие клиента об итоге обработки запроса: успех, ошибка клиента, ошибка сервера или перенаправление.

Зачем нужно

Правильные статус-коды критичны для REST API: они позволяют клиенту (браузеру, мобильному приложению) автоматически обрабатывать ответы без парсинга тела. 200 vs 201, 401 vs 403, 404 vs 422 — каждый код имеет конкретную семантику. Неправильные коды ломают клиентскую логику и нарушают HTTP-спецификацию.

Где используется

  • REST API — каждый эндпоинт возвращает подходящий код
  • Middleware для обработки ошибок — err.status
  • Frontend — axios/fetch реагирует на статус-код
  • Мониторинг и алертинг — 5xx vs 4xx

Основной контент

1xx — Informational

100 Continue          — сервер принял заголовки, продолжай отправку тела
101 Switching Protocols — переключение на WebSocket

2xx — Success

200 OK                — успешный GET, PUT, PATCH
201 Created           — успешный POST (создан ресурс)
202 Accepted          — запрос принят, обрабатывается асинхронно
204 No Content        — успешный DELETE (нет тела ответа)
206 Partial Content   — ответ на Range-запрос (видео стриминг)

3xx — Redirection

301 Moved Permanently — ресурс перемещён навсегда (SEO редирект)
302 Found             — временный редирект
304 Not Modified      — ETag/Last-Modified совпали, отдать из кеша
307 Temporary Redirect — как 302, но метод сохраняется (POST → POST)
308 Permanent Redirect — как 301, но метод сохраняется

4xx — Client Error

400 Bad Request       — невалидные данные, неправильный запрос
401 Unauthorized      — не аутентифицирован (нет токена)
403 Forbidden         — аутентифицирован, но нет прав
404 Not Found         — ресурс не найден
405 Method Not Allowed — GET на POST-only endpoint
408 Request Timeout   — клиент слишком долго отправляет данные
409 Conflict          — конфликт (дублирующийся email)
410 Gone              — ресурс удалён навсегда
413 Payload Too Large — тело запроса слишком большое
422 Unprocessable Entity — данные парсятся но не валидны (Joi ошибка)
429 Too Many Requests — превышен rate limit

5xx — Server Error

500 Internal Server Error — непредвиденная ошибка сервера
501 Not Implemented       — метод не реализован
502 Bad Gateway           — upstream вернул невалидный ответ
503 Service Unavailable   — сервер перегружен или на обслуживании
504 Gateway Timeout       — upstream не ответил вовремя

В Express

// 200 OK (по умолчанию при res.json())
res.json({ data: users });

// 201 Created
const user = await UserService.create(req.body);
res.status(201).json(user);

// 204 No Content
await UserService.delete(req.params.id);
res.status(204).send;

// 400 Bad Request — невалидные данные
if (!req.body.email) {
  return res.status(400).json({ error: 'email is required' });
}

// 401 vs 403
if (!req.headers.authorization) {
  return res.status(401).json({ error: 'Authentication required' });
}
if (req.user.role !== 'admin') {
  return res.status(403).json({ error: 'Admin access required' });
}

// 404 Not Found
const user = await UserService.getById(req.params.id);
if (!user) return res.status(404).json({ error: 'User not found' });

// 409 Conflict
try {
  const user = await UserService.create(req.body);
  res.status(201).json(user);
} catch (err) {
  if (err.code === 'UNIQUE_VIOLATION') {
    return res.status(409).json({ error: 'Email already in use' });
  }
  next(err);
}

// 429 Too Many Requests
res.status(429)
  .set('Retry-After', '60')
  .json({ error: 'Too many requests, retry after 60 seconds' });

// 500 Internal Server Error (через error middleware)
app.use((err, req, res, next) => {
  res.status(err.status || 500).json({ error: err.message });
});

401 vs 403 — частая путаница

401 Unauthorized (плохое название):
  → Пользователь НЕ аутентифицирован
  → Токена нет или он невалидный
  → "Кто ты? Представься"

403 Forbidden:
  → Пользователь аутентифицирован
  → Но не имеет прав на этот ресурс
  → "Я знаю кто ты, но тебе сюда нельзя"

Частые ошибки

  • 200 для ошибок{ status: 'error', message: '...' } с кодом 200 ломает клиентов, ожидающих ошибочный HTTP-статус
  • 500 для ошибок клиента — невалидный input → 400, не найдено → 404; 500 только для непредвиденных серверных ошибок
  • 404 вместо 403 — скрывать существование ресурса через 404 иногда правильно (security), но в API лучше 403
  • 201 без Location заголовка — при 201 рекомендуется Location: /api/users/{id} для сообщения где новый ресурс

Связанные темы

Ресурсы