Методы, статусы и заголовки во всех версиях одни и те же. Меняется то, как байты едут по сети.
Проблемы HTTP/1.1
- В одном TCP-соединении запросы идут по очереди: пока не пришёл ответ на первый, второй ждёт. Это head-of-line blocking на уровне HTTP.
- Браузер открывает до ~6 соединений на хост, чтобы грузить параллельно. Каждое соединение это свой TCP и TLS handshake.
- Заголовки текстом и повторяются в каждом запросе (куки, User-Agent).
Отсюда старые хаки: склейка бандлов, CSS-спрайты, раздача статики с нескольких поддоменов (domain sharding).
HTTP/2
- Бинарные фреймы вместо текста.
- Мультиплексирование: много потоков (streams) в одном TCP-соединении, фреймы разных ответов перемешиваются. Запросы больше не ждут друг друга на уровне HTTP.
- HPACK: сжатие заголовков, повторяющиеся заголовки передаются индексом из таблицы.
- Одно соединение на хост, поэтому domain sharding вредит: лишние рукопожатия и разорванная приоритизация.
- Server Push был в спецификации, но не прижился: Chrome и Firefox его убрали. Замена:
103 Early Hintsи<link rel="preload">.
Браузеры поддерживают HTTP/2 только поверх TLS. Версия выбирается на рукопожатии через расширение ALPN (h2).
Остаётся проблема: всё идёт в одном TCP. Если потерялся один пакет, TCP не отдаст приложению следующие, пока не дождётся повтора. Все потоки встают. Это head-of-line blocking на уровне TCP, и на плохой мобильной сети HTTP/2 может быть даже хуже нескольких соединений HTTP/1.1.
HTTP/3 и QUIC
HTTP/3 работает поверх QUIC, а QUIC поверх UDP. QUIC сам делает то, что раньше делал TCP (надёжная доставка, контроль перегрузки), но:
- Потоки независимы на транспортном уровне: потеря пакета тормозит только свой поток.
- TLS 1.3 встроен в QUIC, рукопожатие транспорта и шифрования совмещено: новое соединение за 1 RTT, повторное может за 0-RTT. Для сравнения: TCP + TLS 1.3 это 2 RTT.
- Миграция соединения: соединение определяется Connection ID, а не парой IP и порт. Переход с Wi-Fi на мобильную сеть не рвёт соединение.
- Сжатие заголовков QPACK (вариант HPACK, устойчивый к доставке не по порядку).
- Шифруются и большинство служебных полей, middlebox-ы не могут в них вмешиваться.
Как браузер узнаёт, что сервер умеет HTTP/3: первый запрос идёт по HTTP/2 или 1.1, сервер отвечает заголовком Alt-Svc: h3=":443", и дальше браузер пробует QUIC. Другой способ: DNS-запись HTTPS. Если UDP заблокирован (бывает в корпоративных сетях), браузер откатывается на TCP.
Сравнение
| HTTP/1.1 | HTTP/2 | HTTP/3 | |
|---|---|---|---|
| Транспорт | TCP | TCP | QUIC (UDP) |
| Формат | текст | бинарный | бинарный |
| Параллельность | несколько соединений | потоки в одном соединении | независимые потоки |
| HOL blocking | HTTP и TCP | только TCP | нет на транспорте |
| Сжатие заголовков | нет | HPACK | QPACK |
Частые ошибки
- «HTTP/3 ненадёжен, потому что UDP». Надёжность обеспечивает QUIC.
- «С HTTP/2 бандлить не нужно вообще». Сотни мелких модулей всё равно дороже из-за накладных расходов и худшего сжатия; бандлы просто можно делить мельче.
- «HTTP/2 решил head-of-line blocking полностью». Только на уровне HTTP.
Что спросят на собесе
- Что такое мультиплексирование и чем HTTP/2 лучше HTTP/1.1?
- Что такое head-of-line blocking и как его решают HTTP/2 и HTTP/3?
- Почему HTTP/3 работает поверх UDP?
- Какие оптимизации HTTP/1.1 стали вредны с HTTP/2?