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. Классы статус-кодов

КлассДиапазонЗначение
1xx100–199Информационные (продолжение процесса)
2xx200–299Успешные (запрос выполнен)
3xx300–399Перенаправление (нужно ещё одно действие)
4xx400–499Ошибка клиента (клиент сделал что-то не так)
5xx500–599Ошибка сервера (сервер не смог обработать)

Простая шпаргалка

1xx → «Подожди, работаю»
2xx → «Всё хорошо, вот результат»
3xx → «Ищи там, а не здесь»
4xx → «Ты сделал что-то не так»
5xx → «Я (сервер) сломался»

3. Класс 1xx — Информационные

КодНазваниеКогда встречается
100ContinueКлиент может продолжить отправку большого тела запроса
101Switching ProtocolsПереключение на WebSocket
102ProcessingСервер обрабатывает запрос (долгая операция)

На практике 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: /maintenance

304 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 → 410

422 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 запросов быстро → ожидать 429

7. Класс 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 от backend

9. Как тестировать статус-коды

В Postman

javascriptjavascript
// Проверки в 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

typescripttypescript
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. Частые ошибки в статус-кодах

Неверный кодПравильный кодСитуация
200201При успешном создании ресурса (POST)
200204При успешном DELETE (нет тела ответа)
400401Нет токена авторизации
401403Токен есть, но нет прав
400422Данные корректны технически, но нарушают бизнес-правила
404410Ресурс намеренно и навсегда удалён
500400Unhandled exception из-за невалидных данных

Итог

СТАТУС-КОД — это первое что смотрим в ответе API

Правило трёх "Ч":
ЧТО ХОТЕЛИ:   2xx — получили
ЧТО-ТО НЕ ТАК: 4xx — мы виноваты
ЧЁРТ ПОБЕРИ:  5xx — сервер виноват

Главные для QA:
200 / 201 / 204 → всё хорошо
400 → исправь запрос
401 → авторизуйся
403 → нет прав
404 → не существует
409 → конфликт (дубль)
422 → бизнес-ошибка
500 → БАГ на сервере (всегда создавай баг-репорт!)