# HTTP/1.1, HTTP/2, HTTP/3 _Сеть: L4 и выше · LinuxLab Knowledge Base_ **TL;DR:** HTTP/1.1 - текстовый протокол с keep-alive. HTTP/2 - бинарный с мультиплексированием в одном TCP-соединении. HTTP/3 = HTTP/2-семантика поверх QUIC/UDP без TCP-head-of-line blocking. ## Зачем три версии HTTP - прикладной протокол поверх [[tcp-handshake|TCP]] (или [[udp-basics|UDP]] в HTTP/3). Обновлялся дважды чтобы решить накопленные проблемы производительности. Версии **взаимно понимаемы** через [[tls-handshake|TLS]] ALPN: клиент и сервер договариваются при handshake'е. ## HTTP/1.1 (1997) Текстовый запрос-ответ. Каждый запрос - один request/response через CRLF-разделители: ``` GET /api/users HTTP/1.1 Host: example.com User-Agent: curl/8.0 Accept: application/json ``` ``` HTTP/1.1 200 OK Content-Type: application/json Content-Length: 42 {"users":[{"id":1,"name":"alice"}]} ``` **Главные фичи:** - **Host header** - один IP, много vhost'ов - **Keep-alive** - переиспользовать TCP-соединение для нескольких запросов (по дефолту on) - **Chunked transfer encoding** - стриминг ответа без знания Content-Length заранее - **Pipelining** - слать запросы не дождавшись ответа (на практике выключают - HoL blocking, см. ниже) **Главная боль HTTP/1.1:** - Один запрос за раз в одном соединении (Head-of-Line blocking на L7) - Браузеры открывают 6+ TCP-соединений к одному хосту чтобы качать параллельно - Заголовки повторяются в каждом запросе (cookies, user-agent…) ## HTTP/2 (2015) - бинарный мультиплекс Тот же `GET /api/users` остался, но **формат бинарный**: - Один TCP-соединение содержит много **streams** (логических каналов) - Streams мультиплексируются - кадры из разных запросов чередуются - **HPACK** - сжатие заголовков; повторяющиеся куки/токены передаются индексом, не строкой - **Server Push** - сервер может слать ресурсы до запроса клиента (на практике задеприкейтили - редко полезно) - **Stream priority** - сказать «этот CSS важнее, чем картинка» В сухом остатке: один TCP-сокет на host вместо 6, заголовки сжаты, параллельные запросы не блокируются друг другом на L7. **Но!** Если потерялся пакет в TCP - **все streams в этом соединении блокируются** до ретрансмита. Это TCP head-of-line blocking, который HTTP/2 *не решает*, только выявляет. ## HTTP/3 (2022) - QUIC заменяет TCP Та же бинарная семантика, что HTTP/2, но транспорт - **QUIC поверх UDP**: - Каждый stream живёт независимо - потеря пакета в одном стриме не блокирует другие (нет TCP-HoL) - Handshake = 1 RTT (или 0 RTT для повторных подключений) - в QUIC TLS встроен - Connection migration - смена IP (Wi-Fi → 4G) не разрывает соединение, QUIC привязывается к Connection ID, не к 5-tuple - Шифрование обязательно Минусы HTTP/3: - UDP часто рейтлимитится firewall'ами и LB - Сложнее наблюдать (нет нативного netstat для QUIC до недавно) - Требует ALPN `h3` через TLS 1.3 ## Сравнение | Свойство | HTTP/1.1 | HTTP/2 | HTTP/3 | |------------------------|----------|---------|--------| | Транспорт | TCP | TCP | QUIC/UDP | | Формат | текст | бинарь | бинарь | | Multiplexing | нет | да | да | | Head-of-line blocking | L4 + L7 | L4 (TCP)| нет | | Сжатие заголовков | нет | HPACK | QPACK | | TLS | опц. | опц. | обязателен | | Server Push | нет | да* | да* | *устарел, не используется ## Где видно в tcpdump ```bash # HTTP/1.1, текст в plain tcpdump -i any -nn -A 'tcp port 80' # HTTP/2, бинарь, видно ALPN-маркер 'h2' в ClientHello tcpdump -i any -nn 'tcp port 443' -X # HTTP/3, UDP/443 tcpdump -i any -nn 'udp port 443' ``` ## Какой выбрать в 2026 - **CDN / edge** - HTTP/3 для пользователей через Wi-Fi, fallback HTTP/2 - **internal API** - HTTP/2 (один долгоживущий соединение, gRPC по нему) - **legacy / простота** - HTTP/1.1, парсинг из любого языка двумя строками ## Когда что-то пошло не так - **HTTP/2 RST_STREAM rapid-reset** - DDoS-вектор 2023; патчи в nginx/envoy - **QUIC заблокирован firewall'ом** - падение в HTTP/2 (Alt-Svc) - **HPACK bomb** - вредоносный Huffman через сжатие заголовков; обновляться - **Header limit** - HTTP/2 по умолчанию 16KB заголовков; `large request` не пройдёт без увеличения ## Команды ```bash curl -v --http1.1 https://example.com/ ``` Принудительно HTTP/1.1, видно request/response в plain ```bash curl -v --http2 https://example.com/ ``` HTTP/2 - смотри 'using HTTP2' в выводе и stream IDs ```bash curl -v --http3 https://example.com/ ``` HTTP/3 - нужен curl собранный с поддержкой QUIC (--with-quic) ```bash openssl s_client -alpn h2,http/1.1 -connect example.com:443 < /dev/null 2>&1 | grep -i alpn ``` Что предлагает сервер по ALPN - h2 vs http/1.1 ```bash ss -tnH state established '( sport = :443 )' | head ``` Активные TLS-соединения - не различает версии HTTP, но видно сколько их ## См. также - [TCP three-way handshake](/kb/tcp-handshake.md) - [TLS handshake](/kb/tls-handshake.md) - [WebSocket - bidirectional поверх HTTP](/kb/websocket.md) - [HTTP/2 internals - binary framing, HPACK, stream multiplexing](/kb/http2-internals.md) - [curl - HTTP-клиент из терминала](/kb/cmd-curl.md) - [QUIC и HTTP/3 - современный транспорт поверх UDP](/kb/quic-http3.md)