Skip to main content

HTTP коди статусів

HTTP коди статусів - це тризначні числа, які сервер повертає в кожній HTTP-відповіді, щоб повідомити клієнту що сталося з його запитом.

Теорія

TL;DR

  • Уяви їх як повідомлення про доставку пошти: 200 = доставлено, 404 = адреса не існує, 500 = пошта сама зламала посилку
  • Перша цифра визначає категорію: 2xx успіх, 3xx перенаправлення, 4xx помилка клієнта, 5xx помилка сервера
  • fetch() встановлює response.ok в true тільки для 2xx
  • 401 = не автентифікований (потрібен вхід), 403 = автентифікований, але без дозволу
  • Правило: бачиш 4xx - виправляй запит, бачиш 5xx - чекай або пиши серверній команді

Швидкий приклад

javascript
// Express.js - запустити: npm init -y && npm i express && node server.js const express = require('express'); const app = express(); app.get('/', (req, res) => res.status(200).send('Success')); // 200 OK app.get('/missing', (req, res) => res.status(404).send('Not found')); // 404 Not Found app.get('/error', (req, res) => { throw new Error(); }); // 500 Internal Server Error app.listen(3000); // curl localhost:3000/ → 200 // curl localhost:3000/missing → 404 // curl localhost:3000/error → 500

Перший аргумент res.status() - це число, яке Express записує в статусний рядок відповіді перед відправкою заголовків.

П'ять категорій

Специфікація HTTP групує всі коди за першою цифрою:

  • 1xx (Інформаційні) - сервер прийняв запит і ще обробляє. Рідко трапляються на практиці. Приклад: 100 Continue.
  • 2xx (Успіх) - запит виконано. 200 для стандартного OK, 201 коли ресурс створено, 202 коли задача запущена але ще не завершена.
  • 3xx (Перенаправлення) - ресурс переміщено. 301 постійне (оновлюй посилання), 302 тимчасове (перевіряй оригінальний URL).
  • 4xx (Помилка клієнта) - щось у запиті неправильне. 400 невалідні дані, 401 не автентифікований, 403 автентифікований але без дозволу, 404 не знайдено, 429 забагато запитів.
  • 5xx (Помилка сервера) - запит нормальний, але сервер впав. 500 загальна помилка, 503 тимчасово недоступний.

Коли який код використовувати

  • Користувач надіслав валідні дані і ресурс створено → 201 Created
  • Запитуваний ресурс не існує → 404 Not Found
  • Запит без валідного токена → 401 Unauthorized
  • Токен валідний, але роль не має доступу → 403 Forbidden
  • База даних впала → 500 Internal Server Error
  • Технічне обслуговування → 503 Service Unavailable
  • Асинхронна задача поставлена в чергу → 202 Accepted

Типові помилки

Повертати 200 при помилках валідації. Це найпоширеніша помилка в джуніорських API. Клієнт отримує 200 і вважає що все збережено. База даних відхиляє дані, нічого не зберігається, і ніхто не розуміє чому.

javascript
// Неправильно - обманюємо клієнта app.post('/users', (req, res) => { if (!req.body.email) res.status(200).send('OK'); }); // Правильно app.post('/users', (req, res) => { if (!req.body.email) return res.status(400).send('Email required'); });

Відправляти 500 на будь-яку помилку. Якщо користувач надіслав невалідний токен і ти повертаєш 500, логи заповнюються хибними тривогами, а фронтенд-команда не знає що проблема в токені. 4xx для помилок клієнта, 5xx для помилок сервера.

javascript
// Неправильно app.use((err, req, res, next) => res.status(500).send('Error')); // Правильно app.use((err, req, res, next) => { if (err.name === 'ValidationError') return res.status(400).send(err.message); if (err.name === 'UnauthorizedError') return res.status(401).send('Invalid token'); res.status(500).send('Server error'); });

Ігнорувати 429 у циклах запитів. Масові запити до API без перевірки на rate limit (обмеження частоти запитів) закінчуються блокуванням IP. Завжди перевіряй 429 і додавай затримку.

javascript
if (res.status === 429) { await new Promise(r => setTimeout(r, 1000 * Math.pow(2, retryCount))); }

Я бачив як продакшн-інтеграція впала через 1000 запитів до GitHub API в циклі без жодної затримки. IP заблокували за 30 секунд.

Де зустрічаються

  • Express.js - res.status(201).json(user) після POST /users
  • React Query - if (!res.ok) throw new Error(res.status) всередині queryFn
  • Next.js API routes - res.status(401).json({ error: 'Unauthorized' }) в middleware
  • Stripe - 200 при успішному платежі, 402 Payment Required при нестачі коштів
  • GitHub API - 404 для неіснуючого репозиторію, 422 при невалідному PR merge

Питання на співбесіді

Q: Яка різниця між 401 і 403?
A: 401 означає що запит не має валідних облікових даних - запропонуй користувачу увійти. 403 означає що дані валідні, але користувач не має дозволу на цей конкретний ресурс.

Q: Коли повертати 202 замість 200?
A: 202 Accepted використовують коли задача поставлена в чергу, але ще не виконана: наприклад, запуск генерації звіту або відправка email у фоні. Клієнт розуміє що треба почекати або перевірити статус пізніше.

Q: Яка різниця між 301 і 308?
A: Обидва постійні перенаправлення. Але 301 дозволяє браузеру змінити POST на GET при перенаправленні, а 308 зберігає оригінальний метод і тіло запиту. 308 безпечніший коли POST-дані мають пройти через redirect.

Q: API gateway повертає клієнтам 502. Що перевіряєш першим?
A: 502 Bad Gateway означає що проксі отримав невалідну відповідь від upstream-сервісу. Перевір чи запущений upstream, подивись його логи, перевір налаштування таймаутів і додай circuit breaker щоб один сервіс не валив весь ланцюжок.

Приклади

Валідація webhook із перевіркою підпису

javascript
// POST /webhook - перевіряємо підпис перед обробкою платіжної події app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(req.body, sig, process.env.ENDPOINT_SECRET); res.status(200).json({ received: true }); // 200: подія оброблена успішно } catch (err) { res.status(400).send(`Signature check failed: ${err.message}`); // 400: невалідні дані від клієнта } });

Валідний webhook повертає 200. Невалідний підпис повертає 400, а не 500 - бо проблема в даних клієнта, а не в збої сервера.

Обробка кодів у fetch() з розрізненням типів помилок

javascript
async function loadUser(id) { const res = await fetch(`/api/users/${id}`); if (res.status === 404) return null; // відсутній користувач - нормальний стан if (res.status === 401) { window.location.href = '/login'; // перенаправляємо на сторінку входу return; } if (!res.ok) throw new Error(`Error: ${res.status}`); // 500 та невідомі коди return res.json(); }

Коли 404 обробляється як нормальний стан, а 401 тригерить редирект, користувач бачить зрозумілу поведінку замість загального повідомлення про помилку.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.