Урок 6 — HTTP: язык интернета
HTTP — это «язык», на котором браузер разговаривает с веб-сервером. На нём же работают API, мобильные приложения, микросервисы. Понять его — значит понять 80% того, что происходит в вашем продакшене.
DNS превратил имя в IP (урок 5), TCP установил надёжное соединение с портом 80/443 сервера (урок 4). Труба готова — теперь по ней потечёт «разговор». HTTP — это язык этого разговора, причём текстовый: его можно читать глазами и писать руками. Именно поэтому дебаг веба доступен любому, кто дочитает этот урок.
1. Что такое HTTP
HTTP — HyperText Transfer Protocol. Изначально создан для передачи HTML-страниц («гипертекста»), но сейчас на нём работают: страницы, API, файлы, видео, чаты, всё что угодно.
Принципы:
- Текстовый. Запросы и ответы — это обычный текст. Можно набрать руками в
telnetилиnc. - Клиент-серверный. Клиент инициирует, сервер отвечает (как в уроке 1).
- Без состояния (stateless). Сервер не помнит твой прошлый запрос. Если нужно — клиент сам шлёт «удостоверение» в каждом запросе (cookie или token).
- Запрос-ответ. Один запрос — один ответ. Не «подписка» и не «поток» (для подписок есть WebSocket).
HTTP работает поверх TCP (а HTTPS — поверх TCP+TLS). По умолчанию HTTP использует порт 80, HTTPS — 443.
2. URL — анатомия адреса
То, что ты вводишь в адресной строке, называется URL (Uniform Resource Locator). У него строго определённая структура:
На сервер ушло всё, кроме fragment (всё, что после #) — это обрабатывается только в браузере и сервер о нём не знает.
3. Что такое запрос
HTTP-запрос — это просто текст. Вот как он выглядит «изнутри», без браузерной обёртки:
GET /users/42 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0
Accept: application/json
Authorization: Bearer eyJhbGc...
Cookie: session=abc123
(пустая строка — конец заголовков)
(тело запроса — для GET обычно пустое)
Структура — три части:
- Стартовая строка: метод + путь + версия HTTP
- Заголовки: мета-информация, ключ-значение
- Тело (body): данные (для POST, PUT, PATCH). Пустое для GET
4. Методы HTTP
Метод говорит серверу, что мы хотим сделать с ресурсом. Их немного, и каждый имеет свой смысл:
| Метод | Что делает | Идемпотентен? |
|---|---|---|
| GET | Получить ресурс. Не меняет состояние сервера | ✓ Да |
| POST | Создать ресурс / отправить данные | ✗ Нет (повторный запрос создаст ещё один) |
| PUT | Полностью заменить ресурс | ✓ Да |
| PATCH | Частично обновить ресурс | ✗ Обычно нет |
| DELETE | Удалить ресурс | ✓ Да (удалить дважды — то же самое) |
| HEAD | Как GET, но без тела ответа — только заголовки | ✓ Да |
| OPTIONS | Узнать, какие методы поддерживает сервер (используется в CORS) | ✓ Да |
«Идемпотентный» — значит «повторение даёт тот же результат». Сделал GET 5 раз — ничего не сломал. Сделал POST 5 раз — у тебя 5 одинаковых записей. Это важно: retry в инфраструктуре безопасны только для идемпотентных запросов.
5. Что такое ответ
HTTP/1.1 200 OK
Date: Wed, 15 May 2026 12:00:00 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 87
Cache-Control: max-age=300
Server: nginx/1.25.0
{"id": 42, "name": "Alice", "email": "alice@example.com"}
Структура та же — стартовая строка (теперь с кодом статуса), заголовки, тело.
6. Коды статуса
Трёхзначное число, которое говорит результат запроса. Группируется по первой цифре:
1xx — Информационные
Редко встречаются в обычной жизни. 101 Switching Protocols — переход на WebSocket.
2xx — Успех
200 OK— всё хорошо, держи ответ201 Created— ресурс создан (часто после POST)204 No Content— успех, но тела нет
3xx — Перенаправления
301 Moved Permanently— навсегда переехал302 Found— временно переехал304 Not Modified— у тебя уже есть свежая версия в кэше
4xx — Ошибка клиента
400 Bad Request— ты прислал ерунду401 Unauthorized— кто ты вообще такой?403 Forbidden— кто ты — знаю, но тебе нельзя404 Not Found— такого нет409 Conflict— конфликт состояний (например, уже существует)429 Too Many Requests— rate limit, притормози
5xx — Ошибка сервера
500 Internal Server Error— у сервера что-то упало502 Bad Gateway— LB получил от backend мусор / backend упал503 Service Unavailable— нет здоровых backend-ов / перегрузка504 Gateway Timeout— backend не ответил вовремя
502 / 503 / 504 — отдельно учиться различать:
- 502: «связь есть, но непонятная фигня от upstream». Чаще — приложение упало или вернуло мусор. Смотри логи приложения.
- 503: «вообще нет здорового upstream». Все pod-ы failed health check, или приложение в graceful shutdown. Смотри readiness probes и autoscaling.
- 504: «upstream не ответил за timeout». Медленный запрос — БД, внешний API. Смотри traces, slow query log.
7. Заголовки
Заголовки — это пары «ключ: значение», которые несут метаданные. Их сотни, но десятка нужно знать наизусть:
| Заголовок | Кто шлёт | Зачем |
|---|---|---|
Host | Клиент | Какой домен открываем (на одном IP может быть много сайтов) |
User-Agent | Клиент | Какой браузер / клиент |
Accept | Клиент | В каком формате хотим ответ (HTML, JSON, XML) |
Authorization | Клиент | Учётка / токен. Обычно Bearer <jwt> |
Cookie | Клиент | Сохранённые сервером значения (сессия и т.п.) |
Content-Type | Оба | В каком формате тело: application/json, text/html |
Content-Length | Оба | Сколько байт в теле |
Cache-Control | Сервер | Как клиенту кэшировать ответ |
Set-Cookie | Сервер | «Установи у себя такую куку» |
Location | Сервер | Куда редиректить (при 3xx) |
X-Forwarded-For | Прокси/LB | Реальный IP клиента (когда позади LB) |
Strict-Transport-Security | Сервер | «Всегда заходи по HTTPS» (HSTS, security-заголовок) |
8. Куки и сессии
HTTP без состояния. Сервер сам по себе не знает, что ты тот же пользователь, который заходил минуту назад. Чтобы запомнить — придумали куки (cookies).
Механика:
- Клиент логинится — отправляет username/password
- Сервер проверяет, создаёт сессию, шлёт ответ с
Set-Cookie: session=abc123 - Браузер запоминает эту куку
- В каждом следующем запросе клиент шлёт
Cookie: session=abc123 - Сервер видит куку, находит сессию, понимает «это Alice»
У кук есть важные атрибуты безопасности:
- HttpOnly — JavaScript не сможет прочитать куку (защита от XSS)
- Secure — кука шлётся только по HTTPS
- SameSite — кука не отправляется при кросс-доменных запросах (защита от CSRF)
- Max-Age / Expires — срок жизни
В современных приложениях вместо «классических сессий с кукой» часто используют JWT-токены в заголовке Authorization. Принцип тот же — клиент несёт удостоверение в каждом запросе.
9. HTTP/1.1 vs HTTP/2 vs HTTP/3
| HTTP/1.1 (1997) | HTTP/2 (2015) | HTTP/3 (2022) | |
|---|---|---|---|
| Формат | Текст | Бинарный | Бинарный |
| Транспорт | TCP | TCP | QUIC поверх UDP |
| Multiplexing | Нет (один запрос — одно соединение) | Да, параллельно в одном TCP | Да, без head-of-line blocking |
| Сжатие заголовков | Нет | HPACK | QPACK |
| Push от сервера | Нет | Да (редко используется) | Нет (убрали как ненужное) |
На практике: современный продакшен — HTTP/2 везде (TLS требует HTTP/2 в новых браузерах). HTTP/3 — растущий стандарт; Cloudflare, Google, Meta уже массово на нём. Учи как «знать о существовании», но HTTP/2 пока главный.
10. REST — стиль API
REST (Representational State Transfer) — это не протокол, а стиль построения HTTP-API. Идея:
- Каждый «ресурс» имеет уникальный URL (
/users/42) - Метод HTTP описывает действие: GET читать, POST создать, PUT/PATCH обновить, DELETE удалить
- Ответы в формате JSON
- Statelessness — каждый запрос самодостаточен
# Получить список пользователей
GET /users
# Получить одного
GET /users/42
# Создать нового
POST /users + body { "name": "Bob" }
# Обновить
PATCH /users/42 + body { "name": "Alice" }
# Удалить
DELETE /users/42
Альтернативы REST — GraphQL (один POST-эндпоинт, гибкая query), gRPC (бинарный, поверх HTTP/2, для микросервисов). Знай о существовании.
11. Что с этим делает DevOps
- Конфигурация LB / Ingress. Reverse proxy маршрутизирует по host + path. Без понимания URL — не настроишь.
- Health checks. ALB / K8s liveness probes делают GET
/healthzи проверяют200 OK. - Логи доступа. Каждая строка лога — это HTTP-запрос: метод, путь, статус, тайминг. Читать обязательно.
- SLO / RED метрики. Rate / Errors / Duration считаются по статус-кодам и latency. 5xx > 0.1% — инцидент.
- Security-заголовки. HSTS, CSP, X-Frame-Options, Referrer-Policy — твоя ответственность настроить.
- CDN.
Cache-Controlопределяет, что и насколько кэшируется на edge. Ошибка в нём — может cache'нуться приватный ответ для всех. - CORS. Когда фронтенд на одном домене зовёт API на другом — нужен правильный
Access-Control-Allow-Origin.
12. Команды и упражнения
curl — лучший друг
# Простой GET
curl https://api.example.com/users/42
# Подробный вывод (с заголовками запроса и ответа)
curl -v https://api.example.com/users/42
# Только заголовки ответа (HEAD)
curl -I https://api.example.com/
# POST с JSON
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer eyJhbGc..." \
-d '{"name": "Alice"}' \
https://api.example.com/users
# Следовать редиректам
curl -L https://example.com
# Сохранить ответ в файл
curl -o page.html https://example.com
# Тайминги — где медленно
curl -w "DNS: %{time_namelookup}s | Connect: %{time_connect}s | TLS: %{time_appconnect}s | Total: %{time_total}s\n" \
-o /dev/null -s https://example.com
HTTPie — дружелюбная альтернатива
# Подсветка JSON, удобный синтаксис
sudo apt install httpie
http GET https://api.example.com/users/42
http POST https://api.example.com/users name=Alice email=alice@example.com
Сделать HTTP-запрос «руками»
nc example.com 80
GET / HTTP/1.1
Host: example.com
Connection: close
# (двойной Enter)
# Сервер ответит сырым HTTP — увидишь заголовки + тело
13. Чек-лист «понимаю это»
- ☐ Разберу URL на части (схема, хост, порт, путь, query)
- ☐ Назову 5 методов HTTP и что они делают
- ☐ Помню коды: 200, 201, 301, 302, 400, 401, 403, 404, 429, 500, 502, 503, 504
- ☐ Различаю 502 / 503 / 504 в дебаге
- ☐ Объясню, что такое заголовок и приведу 5 примеров
- ☐ Понимаю, как куки/токен делают HTTP «stateful»
- ☐ Знаю про HTTP/1.1, HTTP/2, HTTP/3 и что их различает
- ☐ Сделал POST через
curl -X POST -d ... - ☐ Использовал
curl -wдля измерения таймингов
14. Задачи — реши сам (ответы спрятаны)
Задача 1. Разбери URL по частям: https://api.shop.example.com:8443/v2/orders?status=paid&limit=10#top
Схема — https; хост — api.shop.example.com (поддомен api у
shop.example.com); порт — 8443 (нестандартный, поэтому указан явно); путь —
/v2/orders; query-параметры — status=paid и limit=10;
фрагмент — #top (на сервер вообще не отправляется — живёт только в браузере!).
Задача 2. Пользователь дважды случайно нажал «Обновить» на странице заказа — и заказ создался дважды. Какой метод использовали разработчики неправильно и почему?
Создание заказа повесили на GET (или повторили POST без защиты). GET обязан быть безопасным и идемпотентным — только читать, ничего не менять: браузеры свободно повторяют GET при обновлении. Изменяющие действия — POST/PUT/DELETE, плюс защита от повторной отправки. Это не педантизм — это реальные дважды списанные деньги.
Задача 3. Чем 401 отличается от 403? Придумай по житейскому примеру на каждый.
401 Unauthorized — «я не знаю, кто ты»: нет/просрочен токен или логин. Пример: пытаешься войти в подъезд без ключа. 403 Forbidden — «я знаю, кто ты, но тебе нельзя»: аутентифицирован, но нет прав. Пример: ключ от подъезда есть, но квартира соседа заперта для тебя. В дебаге: 401 → чини аутентификацию, 403 → чини права/роли.
Задача 4. Мониторинг показывает всплеск 502 от твоего Nginx. Что это значит и где искать проблему — в Nginx или за ним?
502 Bad Gateway = Nginx (прокси) жив и отвечает, но приложение за ним вернуло мусор или не отвечает вовсе (упало, перезапускается, не слушает порт). Искать за прокси: живо ли приложение, слушает ли свой порт (плейбук урока 4). Сравни: 503 — «перегружен/недоступен временно», 504 — «бэкенд слишком долго думал» (таймаут).
Задача 5. Ты залогинился на сайте, закрыл вкладку, открыл снова — и всё ещё залогинен. Как это работает, если HTTP «без памяти»?
При логине сервер выдал cookie (заголовок Set-Cookie), браузер
сохранил её и теперь автоматически прикладывает к каждому запросу на этот домен
(заголовок Cookie). Сервер по ней узнаёт твою сессию. Сам HTTP остался stateless —
«память» живёт в паре cookie ↔ сессия на сервере.
Задача 6. REST-вопрос: спроектируй методы и пути для операций над товарами интернет-магазина: список, один товар, создать, изменить цену, удалить.
GET /products — список; GET /products/42 — один;
POST /products — создать (тело с данными); PATCH /products/42 —
частично изменить (цену); DELETE /products/42 — удалить. Существительные во
множественном числе в пути, действие выражается методом — это и есть REST-стиль.
Один тревожный факт: всё, что ты писал в этом уроке через curl http://…, летело по
сети открытым текстом — любой узел по пути (Wi-Fi кафе, провайдер, роутер) мог
прочитать твои заголовки, куки и пароли. Как интернет решил эту проблему — и что на самом деле
значит «замочек» в браузере — в следующем уроке про HTTPS и TLS. Это самая красивая инженерная
история всего пути.