HTTP/1.1 (1997). Текстовый протокол, постоянные соединения (keep-alive) по умолчанию. Но в одном соединении запросы идут по очереди: следующий ответ ждёт предыдущего — блокировка начала очереди на уровне HTTP. Конвейеризация (pipelining) почти не прижилась. Поэтому браузеры открывают около 6 соединений на домен, а сайты раньше раскидывали статику по поддоменам, склеивали файлы и рисовали спрайты.
HTTP/2 (2015). Смысл тот же — методы, заголовки, коды, — меняется передача:
- бинарные кадры вместо текста;
- мультиплексирование — много независимых потоков в одном соединении, кадры перемежаются; не нужны несколько соединений и склейки;
- HPACK — сжатие заголовков с общим словарём: повторяющиеся cookie и user-agent почти ничего не стоят;
- приоритеты потоков и (ныне заброшенный) server push.
Но всё едет по одному TCP: потеря одного пакета задерживает все потоки, пока он не будет переотправлен. На плохих сетях HTTP/2 бывает хуже нескольких соединений HTTP/1.1. gRPC работает поверх HTTP/2.
HTTP/3 (2022) — HTTP поверх QUIC, транспорта на UDP:
- потоки независимы на уровне транспорта — потеря пакета задерживает только свой поток;
- TLS 1.3 встроен: установка соединения и шифрования за 1 RTT вместо 2–3, при повторном подключении 0-RTT;
- соединение определяется идентификатором, а не четвёркой адресов — переживает переход телефона с Wi-Fi на мобильную сеть;
- реализован в пространстве пользователя, поэтому быстрее развивается.
Минусы: UDP иногда режут корпоративные сети (тогда откат на HTTP/2), больше нагрузка на CPU, сложнее отладка.
На практике: между браузером и CDN — HTTP/2 и 3; внутри дата-центра часто HTTP/1.1 с пулом соединений или HTTP/2 для gRPC. Версию выбирают согласованием в TLS (ALPN) и заголовком Alt-Svc для HTTP/3.