Введение
Каждый раз, когда ваш браузер или приложение отправляет запрос к серверу, в ответ приходит трёхзначный числовой код — HTTP статус код. Этот код сообщает, что произошло: запрос выполнен успешно, ресурс переехал, клиент ошибся или сервер сломался.
Знание HTTP кодов — обязательный навык для любого разработчика, работающего с API, веб-приложениями или микросервисами. Без понимания этих кодов вы не сможете корректно обрабатывать ошибки, отлаживать запросы и строить надёжные системы.
В этой статье вы найдёте:
- ✅ Полную таблицу всех основных HTTP статус кодов
- ✅ Описание каждого кода на русском языке
- ✅ Примеры кода для обработки на JavaScript, Python и PHP
- ✅ Типичные ошибки при работе с API
- ✅ FAQ по самым частым вопросам
📋 Содержание
Что такое HTTP статус коды
HTTP статус код (HTTP Status Code) — это трёхзначное число, которое сервер возвращает клиенту в ответ на HTTP-запрос. Код сообщает о результате обработки запроса: был ли он успешен, требуется ли перенаправление, допустил ли клиент ошибку или произошёл сбой на сервере.
Простыми словами:
HTTP статус коды — это язык общения между клиентом и сервером. Клиент спрашивает: «Дай мне данные», а сервер отвечает числом: 200 — «Держи», 404 — «Не нашёл», 500 — «У меня всё сломалось».
Каждый HTTP-ответ содержит статус код в первой строке:
HTTP/1.1 200 OK
Content-Type: application/json
{"message": "Успех!"}
Здесь 200 — это статус код, а OK — текстовое описание (reason phrase).
Структура кодов (5 классов)
Все HTTP статус коды делятся на 5 классов по первой цифре. Зная только первую цифру, вы уже понимаете общий смысл ответа:
| Класс | Диапазон | Значение | Пример |
|---|---|---|---|
| 1xx | 100–103 | Информационные — запрос принят, продолжайте | 100 Continue |
| 2xx | 200–206 | Успех — запрос выполнен успешно | 200 OK |
| 3xx | 300–308 | Перенаправление — нужно дополнительное действие | 301 Moved Permanently |
| 4xx | 400–429 | Ошибка клиента — проблема на стороне клиента | 404 Not Found |
| 5xx | 500–504 | Ошибка сервера — проблема на стороне сервера | 500 Internal Server Error |
Правило большого пальца:
- 2xx — всё хорошо, запрос выполнен
- 3xx — ресурс переехал, иди по новому адресу
- 4xx — вы (клиент) что-то сделали не так
- 5xx — сервер сломался, это не ваша вина
1xx — Информационные коды
Информационные коды сообщают, что сервер принял запрос и продолжает обработку. В повседневной разработке они встречаются редко, но знать их полезно.
| Код | Название | Описание |
|---|---|---|
100 |
Continue | Сервер получил заголовки запроса и клиент может продолжить отправку тела. Используется при отправке больших файлов — клиент сначала спрашивает «можно?», сервер отвечает «давай». |
101 |
Switching Protocols | Сервер переключается на другой протокол по запросу клиента. Самый частый случай — переход с HTTP на WebSocket (заголовок Upgrade: websocket). |
102 |
Processing | Сервер принял запрос, но ещё не завершил обработку. Предотвращает таймаут у клиента при долгих операциях (WebDAV). |
103 |
Early Hints | Позволяет серверу отправить предварительные заголовки (например, Link) до финального ответа. Браузер может начать предзагрузку ресурсов (CSS, JS) раньше. |
2xx — Успех
Коды класса 2xx означают, что запрос клиента был принят и успешно обработан. Это самые желанные коды в ответе API.
| Код | Название | Когда использовать |
|---|---|---|
200 |
OK | Стандартный успешный ответ. Используйте для GET (получение данных), PUT/PATCH (обновление с возвратом результата). |
201 |
Created | Ресурс успешно создан. Используйте для POST, когда создаётся новый объект. В заголовке Location возвращайте URL нового ресурса. |
202 |
Accepted | Запрос принят, но обработка ещё не завершена. Используйте для асинхронных операций: отправка email, генерация отчёта, запуск длительного процесса. |
204 |
No Content | Запрос успешен, но тело ответа пустое. Используйте для DELETE (удаление) или PUT/PATCH, когда возвращать данные не нужно. |
206 |
Partial Content | Сервер возвращает только часть ресурса. Используется для загрузки файлов по частям (заголовок Range), стриминга видео. |
Примеры использования 200 и 201
// 200 OK — получение данных
fetch('/api/users')
.then(res => {
if (res.status === 200) {
return res.json();
}
});
// 201 Created — создание нового ресурса
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Иван' })
}).then(res => {
if (res.status === 201) {
console.log('Пользователь создан');
// Заголовок Location содержит URL нового ресурса
console.log(res.headers.get('Location'));
}
});
⚠️ Частая ошибка: всегда возвращать 200
Многие API на любой запрос возвращают 200 OK и кладут статус ошибки в тело ответа. Это антипаттерн. Используйте правильные коды: 201 для создания, 204 для удаления, 4xx для ошибок клиента.
3xx — Перенаправление
Коды класса 3xx сообщают, что для завершения запроса клиенту нужно выполнить дополнительное действие — обычно перейти по другому URL.
| Код | Название | Описание | Метод сохраняется? |
|---|---|---|---|
301 |
Moved Permanently | Ресурс навсегда перемещён на новый URL. Поисковые системы обновят индекс. Используйте при смене домена или структуры URL. | Нет (может стать GET) |
302 |
Found | Ресурс временно доступен по другому URL. Поисковые системы сохраняют старый URL в индексе. | Нет (может стать GET) |
304 |
Not Modified | Ресурс не изменился с момента последнего запроса. Клиент может использовать кэшированную версию. Экономит трафик. | — |
307 |
Temporary Redirect | Временное перенаправление с гарантией сохранения HTTP-метода. POST останется POST. | Да |
308 |
Permanent Redirect | Постоянное перенаправление с сохранением HTTP-метода. Аналог 301, но метод не изменяется. | Да |
301 vs 302 vs 307 vs 308 — когда какой?
- 301 — навсегда переехали (SEO-редирект, смена домена)
- 302 — временно на другой адрес (A/B тест, техработы)
- 307 — как 302, но гарантирует сохранение метода (POST → POST)
- 308 — как 301, но гарантирует сохранение метода
4xx — Ошибки клиента
Коды класса 4xx означают, что ошибка на стороне клиента. Сервер не может обработать запрос из-за некорректных данных, отсутствия авторизации или обращения к несуществующему ресурсу. Это самый важный класс для API-разработки.
400 Bad Request
Сервер не может обработать запрос из-за некорректного синтаксиса или невалидных данных.
Когда возникает:
- Невалидный JSON в теле запроса
- Отсутствуют обязательные поля
- Неправильный формат данных (email, дата)
// Пример: отправляем невалидный JSON
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: '{ invalid json }'
});
// Ответ: 400 Bad Request
// { "error": "Invalid JSON in request body" }
401 Unauthorized
Клиент не авторизован. Требуется предоставить учётные данные (токен, логин/пароль).
Когда возникает:
- Отсутствует заголовок
Authorization - Токен истёк или недействителен
- Неправильные логин/пароль
// Запрос без токена авторизации
fetch('/api/profile');
// Ответ: 401 Unauthorized
// { "error": "Token is missing or expired" }
// Правильный запрос с токеном
fetch('/api/profile', {
headers: { 'Authorization': 'Bearer eyJhbGciOi...' }
});
// Ответ: 200 OK
403 Forbidden
Сервер понял запрос, но отказывает в доступе. Авторизация пройдена, но прав недостаточно.
Когда возникает:
- Пользователь пытается получить данные другого пользователя
- Роль не имеет доступа к ресурсу (например, обычный пользователь запрашивает админ-панель)
- IP-адрес заблокирован
⚠️ Частая ошибка: путать 401 и 403
401 — «Я не знаю, кто ты. Представься.» (нужна авторизация)
403 — «Я знаю, кто ты, но тебе сюда нельзя.» (нет прав)
404 Not Found
Запрашиваемый ресурс не найден на сервере.
Когда возникает:
- Неправильный URL
- Ресурс был удалён
- Опечатка в endpoint
// Запрос к несуществующему ресурсу
fetch('/api/users/99999');
// Ответ: 404 Not Found
// { "error": "User with ID 99999 not found" }
405 Method Not Allowed
HTTP-метод не поддерживается для данного ресурса.
Когда возникает:
- Отправлен POST на endpoint, который принимает только GET
- Попытка DELETE на ресурс, который нельзя удалять
// Endpoint принимает только GET
fetch('/api/reports', { method: 'DELETE' });
// Ответ: 405 Method Not Allowed
// Заголовок Allow: GET, POST
408 Request Timeout
Сервер устал ждать запрос от клиента. Клиент слишком долго отправлял данные.
409 Conflict
Запрос конфликтует с текущим состоянием сервера.
Когда возникает:
- Попытка создать пользователя с email, который уже занят
- Конфликт версий при одновременном редактировании
// Попытка зарегистрировать существующий email
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: 'ivan@example.com' })
});
// Ответ: 409 Conflict
// { "error": "User with this email already exists" }
413 Payload Too Large
Тело запроса слишком большое. Сервер отказывается его обрабатывать.
Когда возникает:
- Загрузка файла, превышающего лимит
- Слишком большой JSON в теле запроса
415 Unsupported Media Type
Сервер не поддерживает формат данных в запросе.
Когда возникает:
- Отправлен XML, а сервер принимает только JSON
- Отсутствует заголовок
Content-Type
422 Unprocessable Entity
Сервер понял запрос, синтаксис корректен, но не может обработать содержащиеся в нём данные.
Когда возникает:
- Валидация данных не пройдена (email невалидный, возраст отрицательный)
- Бизнес-логика не позволяет выполнить действие
// Отправляем невалидные данные
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: 'not-an-email', age: -5 })
});
// Ответ: 422 Unprocessable Entity
// {
// "errors": {
// "email": "Некорректный формат email",
// "age": "Возраст должен быть положительным числом"
// }
// }
⚠️ 400 vs 422 — когда что?
400 — запрос синтаксически некорректен (сломанный JSON, неправильный формат).
422 — запрос синтаксически корректен, но данные не прошли валидацию бизнес-логики.
429 Too Many Requests
Клиент отправил слишком много запросов за единицу времени (rate limiting).
Когда возникает:
- Превышен лимит запросов к API
- Слишком частые попытки авторизации
// Ответ при превышении лимита
// HTTP/1.1 429 Too Many Requests
// Retry-After: 60
// X-RateLimit-Limit: 100
// X-RateLimit-Remaining: 0
// X-RateLimit-Reset: 1708700000
// Обработка 429 с повторной попыткой
async function fetchWithRetry(url, retries = 3) {
const response = await fetch(url);
if (response.status === 429 && retries > 0) {
const retryAfter = response.headers.get('Retry-After') || 5;
console.log(`Rate limit. Повтор через ${retryAfter}с...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
return fetchWithRetry(url, retries - 1);
}
return response;
}
5xx — Ошибки сервера
Коды класса 5xx означают, что проблема на стороне сервера. Запрос клиента был корректным, но сервер не смог его обработать. Обычно это повод для алерта в мониторинге.
500 Internal Server Error
Универсальная ошибка сервера. Что-то пошло не так, и сервер не может точнее описать проблему.
Причины:
- Необработанное исключение в коде
- Ошибка подключения к базе данных
- Баг в серверной логике
- Не хватает памяти или дискового пространства
// Серверный код (Node.js) — необработанное исключение
app.get('/api/data', async (req, res) => {
// Если DB недоступна, выбросится исключение
const data = await db.query('SELECT * FROM users');
// Без try/catch клиент получит 500
res.json(data);
});
// Правильная обработка
app.get('/api/data', async (req, res) => {
try {
const data = await db.query('SELECT * FROM users');
res.json(data);
} catch (error) {
console.error('DB Error:', error);
res.status(500).json({ error: 'Внутренняя ошибка сервера' });
}
});
501 Not Implemented
Сервер не поддерживает запрошенную функциональность. Endpoint существует, но метод ещё не реализован.
Пример: API в разработке, где некоторые endpoints заглушены.
502 Bad Gateway
Промежуточный сервер (nginx, load balancer, CDN) получил некорректный ответ от upstream-сервера.
Причины:
- Backend-приложение упало или не запущено
- Backend вернул невалидный ответ
- Проблемы с сетью между nginx и backend
503 Service Unavailable
Сервер временно недоступен. Обычно из-за перегрузки или планового обслуживания.
Причины:
- Сервер перегружен запросами
- Плановое обновление (deploy)
- Зависимый сервис недоступен
// Заголовок Retry-After указывает, когда повторить
// HTTP/1.1 503 Service Unavailable
// Retry-After: 120
// { "error": "Сервис временно недоступен. Повторите через 2 минуты." }
504 Gateway Timeout
Промежуточный сервер не дождался ответа от upstream-сервера.
Причины:
- Backend обрабатывает запрос слишком долго
- Тяжёлый SQL-запрос к базе данных
- Зависание внешнего API, от которого зависит backend
⚠️ 502 vs 504 — в чём разница?
502 Bad Gateway — upstream ответил, но ответ некорректный (приложение упало).
504 Gateway Timeout — upstream не ответил вообще в отведённое время (приложение зависло).
В обоих случаях проблема на backend — проверяйте логи приложения и nginx.
Как обрабатывать статус коды в коде
Рассмотрим примеры правильной обработки HTTP кодов на трёх языках.
JavaScript (fetch)
async function apiRequest(url, options = {}) {
const response = await fetch(url, options);
switch (response.status) {
case 200:
case 201:
return await response.json();
case 204:
return null;
case 400:
throw new Error('Некорректный запрос');
case 401:
throw new Error('Необходима авторизация');
case 403:
throw new Error('Доступ запрещён');
case 404:
throw new Error('Ресурс не найден');
case 422: {
const body = await response.json();
throw new Error(`Ошибка валидации: ${JSON.stringify(body.errors)}`);
}
case 429:
throw new Error('Слишком много запросов');
case 500:
throw new Error('Ошибка сервера');
case 502:
throw new Error('Сервер недоступен (Bad Gateway)');
case 503:
throw new Error('Сервис временно недоступен');
case 504:
throw new Error('Таймаут сервера');
default:
throw new Error(`Неизвестная ошибка: ${response.status}`);
}
}
// Использование
try {
const users = await apiRequest('/api/users');
console.log(users);
} catch (error) {
console.error(error.message);
}
Python (requests)
import requests
def api_request(url, method='GET', **kwargs):
response = requests.request(method, url, **kwargs)
if response.status_code == 200:
return response.json()
elif response.status_code == 201:
return response.json()
elif response.status_code == 204:
return None
elif response.status_code == 400:
raise Exception('Некорректный запрос')
elif response.status_code == 401:
raise Exception('Необходима авторизация')
elif response.status_code == 403:
raise Exception('Доступ запрещён')
elif response.status_code == 404:
raise Exception('Ресурс не найден')
elif response.status_code == 422:
errors = response.json().get('errors', {})
raise Exception(f'Ошибка валидации: {errors}')
elif response.status_code == 429:
retry_after = response.headers.get('Retry-After', 5)
raise Exception(f'Rate limit. Повторите через {retry_after}с')
elif response.status_code >= 500:
raise Exception(f'Ошибка сервера: {response.status_code}')
else:
raise Exception(f'Неизвестная ошибка: {response.status_code}')
# Использование
try:
users = api_request('https://api.example.com/users')
print(users)
except Exception as e:
print(f'Ошибка: {e}')
PHP (cURL)
<?php
function apiRequest(string $url, string $method = 'GET', ?array $data = null): mixed
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
if ($data !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json'
]);
}
$response = curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return match (true) {
$statusCode === 200, $statusCode === 201 => json_decode($response, true),
$statusCode === 204 => null,
$statusCode === 400 => throw new Exception('Некорректный запрос'),
$statusCode === 401 => throw new Exception('Необходима авторизация'),
$statusCode === 403 => throw new Exception('Доступ запрещён'),
$statusCode === 404 => throw new Exception('Ресурс не найден'),
$statusCode === 429 => throw new Exception('Слишком много запросов'),
$statusCode >= 500 => throw new Exception("Ошибка сервера: {$statusCode}"),
default => throw new Exception("Неизвестная ошибка: {$statusCode}"),
};
}
// Использование
try {
$users = apiRequest('https://api.example.com/users');
print_r($users);
} catch (Exception $e) {
echo "Ошибка: " . $e->getMessage();
}
Самые частые ошибки при работе с API
✅ Правила хорошего тона
- Используйте правильные коды — не возвращайте 200 для ошибок
- Добавляйте описание ошибки — в теле ответа объясняйте, что пошло не так
- Будьте консистентны — один формат ошибок во всём API
- Не раскрывайте внутренности — не отправляйте stack trace клиенту
- Логируйте 5xx ошибки — это баги, которые нужно чинить
❌ Антипаттерны
- 200 для всего —
{"status": 200, "error": "Not found"}— так делать нельзя - 500 вместо 4xx — если клиент ошибся, возвращайте 4xx, а не 500
- Stack trace в ответе —
{"error": "NullPointerException at line 42..."}— это дыра в безопасности - Игнорирование 429 — не обрабатывать rate limit приведёт к бану IP
- Нет Retry-After — при 429 и 503 всегда возвращайте заголовок
Retry-After
⚠️ Формат ошибок — будьте консистентны
Используйте единый формат ошибок во всём API:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Ошибка валидации данных",
"details": {
"email": "Некорректный формат email",
"age": "Должно быть положительным числом"
}
}
}
FAQ
❓ Чем отличается 401 от 403?
Ответ: 401 Unauthorized означает, что клиент не предоставил учётные данные или они недействительны — нужно авторизоваться. 403 Forbidden означает, что сервер знает, кто вы (авторизация пройдена), но отказывает в доступе — у вас нет прав.
401 → «Кто ты? Покажи пропуск» (нет токена / токен невалидный)
403 → «Я тебя знаю, но сюда нельзя» (нет прав на ресурс)
❓ Когда использовать 200 vs 201 vs 204?
Ответ:
200 OK— для GET, PUT, PATCH, когда возвращаете данные в теле ответа201 Created— для POST, когда создан новый ресурс. Добавьте заголовокLocationс URL нового ресурса204 No Content— для DELETE или когда тело ответа не нужно (успешное обновление без возврата данных)
❓ Что делать при получении 429 Too Many Requests?
Ответ:
- Проверьте заголовок
Retry-After— он указывает, через сколько секунд можно повторить запрос - Реализуйте exponential backoff — увеличивайте паузу между повторами (1с → 2с → 4с → 8с)
- Кэшируйте ответы, чтобы уменьшить количество запросов к API
- Проверьте заголовки
X-RateLimit-LimitиX-RateLimit-Remainingдля контроля лимитов
❓ Чем отличается 502 от 504?
Ответ: Оба кода означают проблему за прокси-сервером (nginx, load balancer), но причины разные:
502 Bad Gateway— upstream-сервер ответил, но ответ некорректный (приложение упало, вернулась ошибка)504 Gateway Timeout— upstream-сервер не ответил вообще за отведённое время (запрос завис, таймаут)
502 → Backend ответил чушь (crash, невалидный ответ)
504 → Backend молчит (зависание, долгий запрос к БД)
Заключение
📝 Сводная таблица HTTP статус кодов
| Класс | Значение | Ключевые коды | Действие клиента |
|---|---|---|---|
| 1xx | Информация | 100, 101, 103 | Продолжить запрос |
| 2xx | Успех | 200, 201, 204 | Обработать ответ |
| 3xx | Перенаправление | 301, 302, 304, 307 | Перейти по новому URL |
| 4xx | Ошибка клиента | 400, 401, 403, 404, 422, 429 | Исправить запрос |
| 5xx | Ошибка сервера | 500, 502, 503, 504 | Повторить позже |
HTTP статус коды — фундамент общения между клиентом и сервером. Правильное использование кодов делает ваш API понятным, предсказуемым и удобным для разработчиков. Неправильное — приводит к часам отладки и бесконечным вопросам от клиентов «а почему не работает?».
💡 Три главных правила:
- Используйте правильные коды — 201 для создания, 204 для удаления, 4xx для ошибок клиента
- Всегда объясняйте ошибку — код + понятное сообщение в теле ответа
- Обрабатывайте все коды на клиенте — не надейтесь, что сервер всегда вернёт 200
🎯 Тестируйте HTTP коды с LightBox API
Хотите проверить, как ваше приложение обрабатывает разные HTTP статус коды?
LightBox API позволяет создать Mock API с любыми статус кодами — настройте ответы 200, 400, 401, 404, 500 и тестируйте обработку ошибок.
- ✓ Настройка любого HTTP статус кода для ответа
- ✓ Разные сценарии ответов для одного endpoint
- ✓ Логирование всех запросов и ответов
- ✓ Бесплатный план для старта
Статья опубликована: 23 февраля 2026
Автор: LightBox API Team