Этап 6 — HTTP/2 и HTTP/3

HTTP/1.1 — двадцатилетний динозавр. HTTP/2 решил его главные проблемы. HTTP/3 пошёл дальше — взял другой транспорт. Понимать разницу — критично, потому что разработчики до сих пор оптимизируют сайты под HTTP/1.1 и теряют в 2-3 раза скорость.

Рабочая ситуация

«Ретро после миграции на HTTP/2: в офисном Wi-Fi сайт стал быстрее в два раза, а у мобильных пользователей в метро — МЕДЛЕННЕЕ, чем был на HTTP/1.1. Метрики не врут». Прежде чем читать: как один и тот же протокол может ускорять в хорошей сети и замедлять в плохой? Подсказка: подумай, что общего у всех запросов страницы в HTTP/2 — и что происходит, когда в сети теряются пакеты. Разгадка — в разделе 6, и она же объясняет, зачем вообще существует HTTP/3.

Что узнаешь — после урока ты сможешь
Вспомни из прошлых уроков

Всё нужное уже в руках: из этапа 4 — что потерянный TCP-сегмент останавливает весь поток до ретрансмита (это станет главным героем урока) и что такое RTT и slow start; из этапа 5 — ALPN, которым клиент и сервер договорились о «h2», и 1-RTT handshake, который QUIC умудрится склеить с транспортным. Из этапа 1 — лимит «6 соединений на хост» в HTTP/1.1 и connection coalescing.

1. Почему HTTP/1.1 — это плохо в 2026

HTTP/1.1 (RFC 2616, 1999) спроектирован для одного запроса за раз:

Браузеры обходят это, открывая 6 параллельных соединений на хост. Каждое — отдельный TCP+TLS handshake. Это медленно и дорого.

2. HTTP/2 — бинарный мультиплекс

RFC 7540 (2015). Главные идеи:

🔢 Бинарный формат

Не текст, а структурированные frames. Парсинг моментальный, ошибок меньше.

🔀 Multiplexing

Сотни запросов одновременно в одном TCP-соединении. Никаких очередей.

🗜️ HPACK

Сжатие заголовков. Повторяющиеся headers занимают 1-2 байта.

⚖️ Priorities

Клиент может сказать «CSS важнее, чем картинка». Сервер шлёт критичное первым.

Frames и streams

HTTP/2-соединение — это поток frames. Каждый frame принадлежит какому-то stream. Один stream = один запрос + ответ.

┌─ HTTP/2 connection (один TCP+TLS) ──────────────┐
│  ┌─ Stream 1: GET /page.html ──────┐            │
│  │  HEADERS frame                  │            │
│  │  DATA frame                     │            │
│  └─────────────────────────────────┘            │
│  ┌─ Stream 3: GET /style.css ─────┐             │
│  │  HEADERS frame                 │             │
│  │  DATA frame                    │             │
│  │  DATA frame                    │             │
│  └────────────────────────────────┘             │
│  ┌─ Stream 5: GET /app.js ────────┐             │
│  │  ...                           │             │
│  └────────────────────────────────┘             │
└──────────────────────────────────────────────────┘
   ↑ Frames из разных streams перемежаются в одном TCP-потоке

ID streams нечётные (1, 3, 5...) для клиент-инициированных, чётные — для server-initiated (push).

Типы frames

FrameЧто несёт
HEADERSЗаголовки запроса/ответа (через HPACK)
DATAТело
SETTINGSПараметры соединения (max streams, window size)
WINDOW_UPDATEFlow control: «я готов принять ещё столько»
PRIORITYПриоритет stream (устарел в HTTP/2 → удалён в /3)
RST_STREAMОтменить stream
PINGKeep-alive / latency check
GOAWAY«Закрываю соединение»
PUSH_PROMISEServer push (устарел)

3. HPACK — сжатие заголовков

Заголовки в HTTP/1.1 — это ~700 байт на запрос (Cookie, User-Agent, Accept, ...). Если ты грузишь 100 ресурсов — это 70 КБ только заголовков, и они повторяются.

HPACK решает это двумя способами:

  1. Статическая таблица. Часто используемые имена заголовков заранее проиндексированы. :method GET = индекс 2. Один байт.
  2. Динамическая таблица. Когда клиент шлёт cookie: session=abc123, он добавляет это в общую таблицу. Сервер тоже добавляет. В следующем запросе клиент шлёт только индекс — например, 62.
  3. Huffman. Значения шифруются Huffman-кодом.

В результате — заголовки сжимаются в 5-10 раз. На запрос вместо 700 байт — 50-100.

4. Flow control в HTTP/2

В TCP flow control работает на уровне соединения. В HTTP/2 — добавляется ещё и на уровне stream. Зачем?

Допустим, ты качаешь огромный файл (stream 1) и одновременно делаешь маленький API-запрос (stream 3). Если канал «забит» большим файлом, мелкий не пройдёт — head-of-line blocking. Поэтому HTTP/2 даёт окно отдельно каждому stream.

WINDOW_UPDATE frame: «по stream X я готов принять ещё N байт».

5. Server Push — было, ушло

HTTP/2 ввёл server push: «сервер заранее знает, что клиент попросит CSS, и шлёт его без запроса». Идея красивая, но на практике не сработала:

Chrome выключил push в 2022. HTTP/3 убрал его. Используй 103 Early Hints вместо него — это решает ту же проблему лучше.

6. Главный недостаток HTTP/2 — TCP HoL blocking

HTTP/2 устранил HoL blocking на уровне HTTP — один stream не блокирует другие. Но он не убрал HoL blocking на уровне TCP:

Все streams идут в одном TCP. Если в TCP потеряется один пакет — TCP останавливается, пока пакет не пересылается. Несмотря на то, что данные для других streams уже могли прийти.

В плохих сетях (мобильный 4G, Wi-Fi на стадионе) это убивает HTTP/2 — он становится медленнее, чем HTTP/1.1 с шестью соединениями.

Аналогия

Одна труба против шести — и почему в плохую погоду выигрывают шесть

HTTP/1.1 — это шесть узких труб: по каждой ползёт один запрос за другим, зато затор в одной не мешает остальным пяти. HTTP/2 — одна широкая труба, в которой все посылки едут вперемешку, помеченные номерами потоков: в хорошей сети это сильно быстрее — не надо строить шесть труб (шесть handshake) и каждая посылка не ждёт очереди. Но труба-то одна, и лежит она на TCP: если один сегмент утонул, заслонка закрывается для всех, пока его не перешлют — даже для посылок, которые уже доплыли. Это и есть TCP head-of-line blocking. QUIC (следующий раздел) строит внутри одной трубы независимые дорожки: утонувшая посылка задерживает только свою дорожку.

7. QUIC — новый транспорт

Google разработал QUIC в 2012, IETF стандартизировал в 2021 (RFC 9000). Это новый транспортный протокол поверх UDP.

Идея: «а если перенесём всё, что делает TCP, на уровень приложения — но умнее?»

Слои: HTTP/2 vs HTTP/3 HTTP/2 HTTP/2 (frames, multiplexing) TLS 1.2/1.3 TCP IP HTTP/3 HTTP/3 (frames, multiplexing) QUIC streams + flow control + TLS 1.3 + congestion control UDP IP QUIC заменил TCP + TLS на собственный транспорт поверх UDP

Что выиграно:

8. QUIC внутри

Connection ID

В TCP соединение идентифицируется 4-tuple (src IP, src port, dst IP, dst port). Сменил сеть — 4-tuple изменился — соединение разорвалось.

В QUIC у соединения собственный connection ID — случайное число, согласованное при handshake. Не зависит от IP. Поэтому при смене сети ничего не разрывается — клиент шлёт пакеты с новым source IP, сервер сопоставляет по connection ID.

Streams в QUIC

QUIC реализует streams сам, не на уровне HTTP. У каждого stream свой sequence number. Потерянный пакет блокирует только свой stream.

QPACK вместо HPACK

HPACK имел проблему: если ты обновляешь динамическую таблицу, и frame с обновлением застрял — следующие запросы блокированы (опять HoL!). QPACK переделан так, чтобы streams могли работать независимо.

0-RTT в QUIC

Как и TLS 1.3 — клиент может вложить данные сразу. Те же ограничения (только идемпотентные).

9. Alt-Svc — как сайт говорит «у меня есть HTTP/3»

Браузер сначала открывает сайт по HTTP/2. Сервер шлёт заголовок:

Alt-Svc: h3=":443"; ma=86400

Это значит: «попробуй HTTP/3 на этом же хосте, порт 443, кэшируй на 24 часа». Браузер в следующих визитах сразу подключается через QUIC.

Альтернатива — DNS-запись HTTPS:

example.com.  HTTPS  1 . alpn="h3,h2"

Браузер узнаёт о HTTP/3 ещё до первого подключения.

10. HTTP/3 frames — другие, но похожие

В HTTP/3 — свой набор frames, упрощённый по сравнению с HTTP/2 (часть работы делает QUIC):

Нет: WINDOW_UPDATE (QUIC сам), PING (QUIC сам), PRIORITY (отдельная extension).

11. Сравнение в цифрах

HTTP/1.1HTTP/2HTTP/3
ТранспортTCPTCPQUIC/UDP
СоединениеДо 6 параллельныхОдноОдно
FormatТекстБинарныйБинарный
MultiplexingНетДа (stream-level)Да + без TCP HoL
Header compressionНетHPACKQPACK
Handshake RTT (новый)2-3 (TCP+TLS)2-31 (QUIC объединяет TCP+TLS)
0-RTTЧерез TLS 1.3Встроено
Connection migrationНетНетДа
ШифрованиеОпциональноОпционально (но всегда HTTPS)Встроено и обязательно

12. Adoption в 2026

По данным Cloudflare / W3Techs (округлённо):

Браузеры (Chrome, Firefox, Safari) все поддерживают HTTP/3 и автоматически переключаются.

13. Подводные камни

UDP блокируется в корпоративных сетях

Старые firewalls режут UDP на порту 443. Браузер пробует HTTP/3, fail-back на HTTP/2. Это медленно при первом подключении. Решение — Alt-Svc Happy Eyeballs.

UDP rate limit

Некоторые провайдеры искусственно режут UDP. QUIC работает медленно.

QUIC замечен «карательно»

В странах с глубокой инспекцией трафика — QUIC может блокироваться, потому что middleboxes не видят, что внутри. С ECH это станет ещё «слепее».

HTTP/3 не везде в облаке

AWS ALB — поддерживает HTTP/2, но не HTTP/3 (на середину 2024). Cloudflare и Fastly — оба. AWS CloudFront — да.

14. Мини-лаба: попробуй прямо сейчас

curl с поддержкой HTTP/3 есть в свежих дистрибутивах (проверь curl --version: флаги HTTP2/HTTP3); если --http3 нет — первые команды всё равно работают:

# Какой протокол согласовался
curl -v --http2 https://example.com 2>&1 | grep -i 'http/'
curl -v --http3 https://www.cloudflare.com 2>&1 | grep -i 'http/'

# Только заголовки + версия
curl -sI -o /dev/null -w '%{http_version}\n' https://example.com

# Alt-Svc — посмотреть, есть ли HTTP/3
curl -sI https://www.cloudflare.com | grep -i alt-svc

# Проверить, реально ли подключаешься по HTTP/3
# Chrome DevTools → Network → колонка Protocol должна показать h3

# Захват QUIC-трафика
sudo tcpdump -i any -nn 'udp port 443'

# Декодировать QUIC в Wireshark — нужны ключи (SSLKEYLOGFILE)
# В Chrome:  export SSLKEYLOGFILE=/tmp/keys.log; google-chrome
Ожидаемый результат

Первый curl напечатает using HTTP/2 и заголовки в нижнем регистре — примета бинарного протокола. В ответе Cloudflare найди alt-svc: h3=":443" — это приглашение перейти на HTTP/3. В DevTools → Network (включи колонку Protocol правой кнопкой по шапке таблицы) у крупных сайтов увидишь h3 — а при первом заходе иногда h2, который на следующих запросах сменится на h3: браузер прочитал Alt-Svc и мигрировал. В tcpdump-захвате QUIC — только нечитаемый UDP на 443: даже тип пакета зашифрован, вот почему сети не умеют вмешиваться в QUIC.

15. Что с этим делает DevOps

16. Задачи самопроверки — реши, потом раскрой ответ

Задача 1. Та самая ситуация из начала урока: после перехода на HTTP/2 мобильные пользователи в метро стали грузиться медленнее, офисные — быстрее. Объясни механизм и предложи решение без отката на HTTP/1.1.

В метро высокие потери пакетов. HTTP/2 везёт все ресурсы в одном TCP-соединении, и каждый потерянный сегмент останавливает ВСЕ потоки до ретрансмита (TCP HoL blocking) — тогда как шесть соединений HTTP/1.1 деградировали независимо. Решение — HTTP/3: QUIC ведёт потоки независимо, потеря тормозит только свой stream. Включить h3 на CDN + Alt-Svc/HTTPS-запись, мобильные браузеры переползут сами.

Задача 2. Во фронтенд-репозитории ты находишь сборку, которая склеивает все JS в один бандл на 4 МБ, спрайтит иконки и раскидывает статику по четырём доменам-шардам. Сайт давно на HTTP/2. Что из этого теперь вредно и почему?

Всё три — оптимизации под HTTP/1.1. Шардинг мешает мультиплексированию и coalescing: браузер строит лишние соединения и хуже приоритизирует. Мегабандл и спрайты ломают кэширование: правка одной строки инвалидирует 4 МБ у всех клиентов, тогда как HTTP/2 спокойно тянет сотни мелких файлов по одному соединению — и кэш обновляется точечно. Убирать шардинг, дробить бандлы, спрайты — только там, где иконки реально меняются вместе.

Задача 3. Пользователь едет в поезде: телефон прыгает между Wi-Fi вагона и LTE. На HTTP/2 каждое переключение — обрыв и повторное соединение, на HTTP/3 видео даже не икает. За счёт чего?

Connection migration. TCP-соединение определяется четвёркой (IP/порты) — сменился IP, умерло соединение, новый handshake. QUIC идентифицирует соединение по Connection ID, а не по адресам: телефон сменил сеть, первый же пакет с новым IP, но старым CID продолжает ту же сессию — без рукопожатий и потери состояния.

Задача 4. Безопасники просят «развернуть инспекцию HTTP/3-трафика на периметре, как мы делали для HTTP/1.1». Что им придётся узнать про QUIC?

QUIC шифрует практически всё, включая транспортные заголовки — извне виден только UDP на 443 с Connection ID. Прозрачная инспекция «по дороге» невозможна by design. Варианты: терминировать QUIC на своём прокси/CDN (легальный MITM с своим сертификатом) и инспектировать расшифрованное, либо блокировать UDP/443 и заставлять клиентов падать на h2 (так делают многие корпоративные сети — браузеры откатываются автоматически).

Задача 5. На собеседовании: «Раз HTTP/2 сжимает заголовки HPACK'ом, почему HTTP/3 понадобился другой алгоритм QPACK?»

HPACK строит динамическую таблицу, которую обе стороны обновляют строго последовательно — это работало, пока TCP гарантировал порядок. В QUIC потоки независимы и приходят в любом порядке: последовательной доставки для таблицы больше нет. QPACK разводит обновления таблицы в отдельные однонаправленные потоки и допускает ссылки с учётом подтверждений — сжатие чуть слабее, зато без блокировок между потоками.

17. Словарик урока

кадр · frame (HTTP/2)бинарная единица протокола: HEADERS, DATA, SETTINGS…; не путать с Ethernet-кадром
поток · streamодин запрос-ответ внутри соединения; потоки едут вперемешку кадрами
мультиплексирование · multiplexingмного параллельных запросов в одном соединении без очереди
блокировка головы очереди · head-of-line blockingодин застрявший элемент держит всех за собой — в HTTP/1.1 на уровне запросов, в HTTP/2 остаётся на уровне TCP
HPACK / QPACKсжатие заголовков словарём: HPACK для упорядоченного TCP, QPACK для неупорядоченного QUIC
QUICтранспорт поверх UDP: потоки, надёжность и TLS 1.3 встроены (RFC 9000)
идентификатор соединения · connection IDQUIC-сессия живёт при смене IP/сети — основа connection migration
миграция соединения · connection migrationпереключение Wi-Fi↔LTE без обрыва сессии
Alt-Svc / запись HTTPSспособы сказать клиенту «у меня есть h3»: заголовок ответа или DNS-запись
server pushсервер сам слал ресурсы вперёд; из HTTP/2 практики ушёл — заменён 103 Early Hints
Мост к следующему уроку

Запрос долетел до edge по h2/h3 — и тут его встречает вышибала. Прежде чем пустить трафик к origin, edge должен решить: это человек или бот? Легитимный запрос или SQL-инъекция? Один из миллиона нормальных или один из миллиона DDoS? Следующий этап — WAF, rate limiting и вся безопасность на границе.

Чек-лист «понимаю это»

HTTP/2 принёс multiplexing и HPACK — но не решил TCP HoL blocking. HTTP/3 уходит на новый транспорт QUIC поверх UDP: 1-RTT handshake, шифрование встроено, connection migration, нет HoL. Server Push мертв — используй 103 Early Hints. Современные оптимизации фронта (никаких sprites/concat) рассчитаны на HTTP/2+. HTTP/3 уже у Cloudflare/Google/Meta, скоро везде.