Lesson 24 of 26
Урок 24 — HTTP Статус-коды
Название: HTTP Статус-коды — язык, на котором сервер отвечает клиенту
Описание: Полный разбор HTTP статус-кодов: 1xx, 2xx, 3xx, 4xx, 5xx. Что каждый код означает, когда он появляется, как с ним работать в тестировании.
Почему это важно для QA: Статус-код — первое, что QA смотрит при анализе ответа API. Без знания их значения невозможно ни писать API-тесты, ни составлять грамотные баг-репорты.
1. Структура HTTP ответа
HTTP/1.1 200 OK ← статусная строка
Content-Type: application/json ← заголовки
Content-Length: 1234
Date: Thu, 25 Jun 2026 10:00:00 GMT
{ ← тело ответа
"id": 42,
"name": "Иван Петров"
}Статус-код — это трёхзначное число, которое сообщает клиенту результат обработки запроса.
2. Классы статус-кодов
| Класс | Диапазон | Значение |
|---|---|---|
| 1xx | 100–199 | Информационные (продолжение процесса) |
| 2xx | 200–299 | Успешные (запрос выполнен) |
| 3xx | 300–399 | Перенаправление (нужно ещё одно действие) |
| 4xx | 400–499 | Ошибка клиента (клиент сделал что-то не так) |
| 5xx | 500–599 | Ошибка сервера (сервер не смог обработать) |
Простая шпаргалка
1xx → «Подожди, работаю»
2xx → «Всё хорошо, вот результат»
3xx → «Ищи там, а не здесь»
4xx → «Ты сделал что-то не так»
5xx → «Я (сервер) сломался»3. Класс 1xx — Информационные
| Код | Название | Когда встречается |
|---|---|---|
| 100 | Continue | Клиент может продолжить отправку большого тела запроса |
| 101 | Switching Protocols | Переключение на WebSocket |
| 102 | Processing | Сервер обрабатывает запрос (долгая операция) |
На практике QA редко работает с 1xx кодами напрямую.
4. Класс 2xx — Успешные
200 OK
Самый распространённый код. Запрос выполнен успешно.
Когда: GET, PUT, PATCH, DELETE (с телом ответа)
Пример: GET /users/42 → 200 + данные пользователя201 Created
Ресурс успешно создан.
Когда: POST (создание нового ресурса)
Пример: POST /users → 201 + созданный пользователь
Важно: должен содержать заголовок Location: /users/43 (URL созданного ресурса)204 No Content
Запрос выполнен, но нет тела ответа.
Когда: DELETE, PUT/PATCH (когда нечего возвращать)
Пример: DELETE /users/42 → 204 (пустой ответ)
Важно: тело ответа пустое (проверяй, что тест не пытается парсить JSON)206 Partial Content
Возвращена часть данных (range request).
Когда: загрузка файлов по частям (Range: bytes=0-1023)
Пример: загрузка видео с определённой позиции5. Класс 3xx — Перенаправления
301 Moved Permanently
Ресурс перемещён на новый URL навсегда. Браузер и поисковики запоминают новый URL.
Когда: http → https редирект, смена структуры URL
Ответ: Location: https://example.com/new-path
Важно: браузер кеширует этот редирект. Для теста нужна очистка кеша.302 Found (Temporary Redirect)
Временное перенаправление. Браузер НЕ запоминает новый URL.
Когда: временное перенаправление (техработы, A/B тест)
Ответ: Location: /maintenance304 Not Modified
Ресурс не изменился, использовать кешированную версию.
Когда: браузер отправляет If-None-Match или If-Modified-Since
Сервер: «Ничего не изменилось — используй кеш»
Тело ответа: пустое (экономия трафика)307 Temporary Redirect / 308 Permanent Redirect
Современные аналоги 302/301. Гарантируют, что метод запроса (POST, PUT) не изменится при редиректе.
307 = временный редирект (метод запроса сохраняется)
308 = постоянный редирект (метод запроса сохраняется)6. Класс 4xx — Ошибки клиента
400 Bad Request
Сервер не понял запрос из-за синтаксической ошибки.
Когда: невалидный JSON, отсутствуют обязательные поля, неверный тип данных
Пример:
POST /users { "email": 12345 } ← email должен быть строкой
→ 400 + { "error": "email must be a string" }401 Unauthorized
Требуется аутентификация. Клиент не аутентифицирован.
Когда: нет токена, истёкший токен, невалидный токен
Пример:
GET /api/profile (без токена) → 401
GET /api/profile (с истёкшим JWT) → 401
ВАЖНО: название вводит в заблуждение! 401 = нет аутентификации
Правильное название было бы «Unauthenticated»403 Forbidden
Сервер понял запрос, пользователь аутентифицирован, но нет прав на выполнение действия.
Когда: у пользователя недостаточно прав (роль User пытается удалить Admin данные)
Пример:
DELETE /api/admin/users/99 (с токеном пользователя) → 403
ОТЛИЧИЕ от 401:
401 = «Кто ты? Докажи»
403 = «Я знаю кто ты, но тебе нельзя»404 Not Found
Ресурс не найден.
Когда: несуществующий ID, неверный URL, удалённый ресурс
Пример:
GET /api/users/99999 → 404 (нет такого пользователя)
GET /api/nonexistent → 404 (нет такого эндпоинта)405 Method Not Allowed
Метод HTTP не поддерживается для данного ресурса.
Пример:
DELETE /api/settings → 405 (нельзя удалять настройки)
Ответ должен содержать Allow: GET, PUT заголовок409 Conflict
Конфликт с текущим состоянием ресурса.
Когда: дублирующееся уникальное поле, нарушение бизнес-правил
Пример:
POST /users { "email": "already@exists.com" } → 409 + "Email уже занят"410 Gone
Ресурс удалён навсегда (в отличие от 404, который может быть временным).
Когда: намеренное удаление ресурса, устаревшая ссылка сброса пароля
Пример:
GET /api/password-reset/expired-token → 410422 Unprocessable Entity
Синтаксис верный, но данные нарушают бизнес-правила.
Когда: данные корректны технически, но некорректны логически
Пример:
POST /orders { "deliveryDate": "2020-01-01" } ← дата в прошлом
→ 422 + { "error": "Дата доставки не может быть в прошлом" }
ОТЛИЧИЕ от 400:
400 = сломан JSON или неверный тип данных
422 = JSON корректный, но нарушена бизнес-логика429 Too Many Requests
Слишком много запросов (rate limiting).
Когда: клиент превысил лимит запросов
Ответ: Retry-After: 60 (подожди 60 секунд)
Тест: отправить 100 запросов быстро → ожидать 4297. Класс 5xx — Ошибки сервера
500 Internal Server Error
Общая ошибка сервера. Что-то пошло не так на сервере.
Когда: необработанное исключение в коде, краш приложения
Признак: в теле ответа может быть stack trace (в dev режиме)
Важно для QA: 500 — это всегда баг! Нужно создать баг-репорт.502 Bad Gateway
Сервер-прокси получил некорректный ответ от upstream-сервера.
Когда: nginx не может достучаться до Node.js backend
Значит: проблема в инфраструктуре, а не в коде приложения503 Service Unavailable
Сервис временно недоступен (перегружен или на техобслуживании).
Когда: слишком большая нагрузка, деплой, плановое обслуживание
Ответ: Retry-After: 3600 (попробуй через час)504 Gateway Timeout
Прокси-сервер не дождался ответа от upstream за отведённое время.
Когда: медленный backend, долгий запрос к БД
Значит: проблема с производительностью8. Полная шпаргалка
2xx УСПЕХ
├── 200 OK → успешный GET, PUT, PATCH
├── 201 Created → успешный POST (создание)
├── 204 No Content → успешный DELETE или PUT без тела
└── 206 Partial Content → частичная загрузка
3xx РЕДИРЕКТЫ
├── 301 Moved Permanently → постоянный редирект (кешируется)
├── 302 Found → временный редирект
└── 304 Not Modified → из кеша (нет изменений)
4xx ОШИБКИ КЛИЕНТА
├── 400 Bad Request → неверный запрос (синтаксис, тип данных)
├── 401 Unauthorized → нет аутентификации
├── 403 Forbidden → нет авторизации (нет прав)
├── 404 Not Found → ресурс не найден
├── 405 Method Not Allowed→ этот метод запрещён
├── 409 Conflict → конфликт (дубль email)
├── 410 Gone → удалён навсегда
├── 422 Unprocessable → бизнес-ошибка валидации
└── 429 Too Many Requests → rate limit превышен
5xx ОШИБКИ СЕРВЕРА
├── 500 Internal Server Error → краш сервера (всегда баг!)
├── 502 Bad Gateway → нет связи с backend
├── 503 Service Unavailable → сервис недоступен
└── 504 Gateway Timeout → timeout от backend9. Как тестировать статус-коды
В Postman
// Проверки в Tests вкладке
pm.test("200 OK", () => pm.response.to.have.status(200));
pm.test("201 Created", () => pm.response.to.have.status(201));
pm.test("Не 500", () => pm.response.to.not.have.status(500));
pm.test("Код в диапазоне 2xx", () => {
pm.expect(pm.response.code).to.be.within(200, 299);
});
В Playwright
import { test, expect } from "@playwright/test";
test.describe("HTTP статус-коды API", () => {
test("GET существующего ресурса → 200", async ({ request }) => {
const response = await request.get("/api/users/1");
expect(response.status()).toBe(200);
});
test("POST создание → 201 + Location заголовок", async ({ request }) => {
const response = await request.post("/api/users", {
data: { name: "Test", email: "test@test.com" },
});
expect(response.status()).toBe(201);
expect(response.headers()["location"]).toMatch(/\/api\/users\/\d+/);
});
test("GET несуществующего ресурса → 404", async ({ request }) => {
const response = await request.get("/api/users/99999");
expect(response.status()).toBe(404);
});
test("запрос без токена → 401", async ({ request }) => {
const response = await request.get("/api/profile");
expect(response.status()).toBe(401);
});
test("недостаточно прав → 403", async ({ request }) => {
const userResponse = await request.post("/api/auth/login", {
data: { email: "user@test.com", password: "UserPass123" },
});
const { token } = await userResponse.json();
const adminResponse = await request.delete("/api/admin/users/1", {
headers: { Authorization: `Bearer ${token}` },
});
expect(adminResponse.status()).toBe(403);
});
});
10. Частые ошибки в статус-кодах
| Неверный код | Правильный код | Ситуация |
|---|---|---|
| 200 | 201 | При успешном создании ресурса (POST) |
| 200 | 204 | При успешном DELETE (нет тела ответа) |
| 400 | 401 | Нет токена авторизации |
| 401 | 403 | Токен есть, но нет прав |
| 400 | 422 | Данные корректны технически, но нарушают бизнес-правила |
| 404 | 410 | Ресурс намеренно и навсегда удалён |
| 500 | 400 | Unhandled exception из-за невалидных данных |
Итог
СТАТУС-КОД — это первое что смотрим в ответе API
Правило трёх "Ч":
ЧТО ХОТЕЛИ: 2xx — получили
ЧТО-ТО НЕ ТАК: 4xx — мы виноваты
ЧЁРТ ПОБЕРИ: 5xx — сервер виноват
Главные для QA:
200 / 201 / 204 → всё хорошо
400 → исправь запрос
401 → авторизуйся
403 → нет прав
404 → не существует
409 → конфликт (дубль)
422 → бизнес-ошибка
500 → БАГ на сервере (всегда создавай баг-репорт!)