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

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

Дочитали статтю?