Сети и протоколы
HTTP дизайн: приоритеты, WebTransport и семантическая корректность
HTTP мультиплексирует потоки. Но без приоритетов сервер стримит их в порядке прихода — что может поставить низкоприоритетное изображение перед блокирующим рендеринг CSS. RFC 9218 заменяет брошенное дерево приоритетов HTTP/2 двухпольным сигналом срочности. Тем временем WebTransport превращает QUIC-соединение в универсальный двусторонний туннель — а семантические ошибки в статус-кодах и заголовках Vary тихо ломают кэширование CDN для миллионов пользователей.
RFC 9218: расширяемые приоритеты
Оригинальная схема приоритетов HTTP/2 (деревья зависимостей с весами, RFC 7540 § 5) была сложной и плохо реализованной. Браузеры и серверы расходились в интерпретации — Cloudflare сообщал, что в некоторых развёртываниях приоритеты делали производительность хуже, чем их отсутствие, потому что несовпадающие реализации заставляли серверы задерживать высокоприоритетные потоки, обслуживая мусор.
RFC 9218 (Extensible Priorities for HTTP) объявляет схему на основе деревьев устаревшей и определяет более простой двухпольный сигнал:
Priority: u=0, iu(urgency, 0–7): меньшее число = выше приоритет.u=0для блокирующего рендеринг HTML,u=1для критического CSS,u=3для стилей,u=5для асинхронных скриптов и шрифтов,u=7для фоновой предзагрузки.i(incremental flag): если выставлен, сервер стримит этот ответ инкрементально — отправляет кусок, потом переключается на потоки с более высокой срочностью, потом возвращается. Используется для больших тел, где частичные данные уже полезны.
Клиент шлёт заголовок Priority: (HTTP/2 и HTTP/3) или фрейм PRIORITY_UPDATE (HTTP/3). Сервер учитывает их при планировании порядка отправки DATA-фреймов по потокам.
Поддержка в браузерах по состоянию на 2026: Chrome, Edge, Safari и Firefox поддерживают Priority header. Cloudflare, Fastly и крупные CDN включили его. Зафиксированные улучшения загрузки страниц: до 37% в некоторых сценариях Cloudflare (за счёт доставки блокирующих рендеринг ресурсов перед изображениями).
Почему это работает
Почему старое дерево приоритетов провалилось. Дерево зависимостей RFC 7540 позволяло клиентам объявлять, что поток #5 зависит от потока #3 с весом 32. Серверы должны были пропорционально распределять пропускную способность. На практике: реализации браузеров вычисляли деревья по-разному; серверные реализации не соглашались с семантикой весов; а edge-узлы CDN — которые обычно проксируют без переинтерпретации приоритетов — полностью игнорировали это. Результат: сложная возможность протокола, не дающая никакой стабильной пользы. Двухпольная модель RFC 9218 (срочность + инкрементальность) достаточно проста, чтобы все реализации сошлись в семантике.
MASQUE и QUIC-датаграммы
MASQUE (Multiplexed Application Substrate over QUIC Encryption) — семейство протоколов IETF, использующих HTTP/3 как туннелирующий слой:
- CONNECT-UDP (RFC 9298): клиент отправляет CONNECT-UDP запрос к HTTP/3-прокси; тело запроса становится туннелем для инкапсулированного UDP-трафика.
- CONNECT-IP: туннелирует IP-пакеты, реализуя полноценный VPN IP-over-QUIC.
iCloud Private Relay Apple использует MASQUE: трафик проходит через Apple Relay 1 (видит IP, не контент) → Apple Relay 2 (видит контент, не IP) → origin. Это разделяет доверие между двумя провайдерами: ни один не может корреляционно связать IP и контент.
QUIC DATAGRAM frames (RFC 9221) несут ненадёжные зашифрованные полезные нагрузки внутри QUIC-соединения — отправляются однократно, без повторной передачи при потере. Это позволяет:
- Медиа в реальном времени со строгим бюджетом задержки (голос, видео — где повторная передача приходит слишком поздно).
- Обновления игрового состояния, где пропущенное обновление позиции безвредно, а задержанное — ошибочно.
WebTransport (W3C + RFC 9298-related) предоставляет браузерному JavaScript полные возможности QUIC: и надёжные потоки (как WebSocket), и ненадёжные датаграммы (как UDP) со страницы браузера. В отличие от WebSocket, WebTransport поддерживает несколько конкурентных потоков на соединение и не требует танца апгрейда. Chromium поставляет WebTransport; Firefox 124+ тоже; Safari за флагом по состоянию на 2026.
- WebTransport — надёжные потоки
- Да (несколько, мультиплексированных)
- WebTransport — ненадёжные датаграммы
- Да (QUIC DATAGRAM)
- WebSocket — надёжный
- Да (один двусторонний канал)
- WebSocket — ненадёжные датаграммы
- Нет
- SSE — надёжный
- Только сервер → клиент
- Поддержка браузерами WebTransport (2026)
- Chrome, Edge, Firefox 124+; Safari за флагом
Схемы аутентификации
Современные веб-приложения используют Authorization: Bearer <token> с JWT или непрозрачным сессионным токеном. HTTP-слой транспортирует учётные данные; OAuth 2.0 / OIDC определяет, как получаются токены.
- Bearer-токены в заголовках — правильно. Токены в HTTP-заголовках не утекают через
Referer, историю браузера или логи доступа сервера (которые логируют URL, но обычно скрывают заголовки). - Токены в URL — опасно.
?token=abcпоявляется в заголовкахReferer, отправляемых к сторонним ресурсам, в истории браузера, в логах доступа CDN и обратных прокси, а также в аналитических системах. Никогда не помещайте конфиденциальные учётные данные в query string. - Basic auth (
Authorization: Basic base64(user:pass)) — остаётся для инструментов внутренних API. Digest auth фактически устарел. - WWW-Authenticate — ответ 401 включает этот заголовок, чтобы сообщить клиенту, какую схему использовать и с какими параметрами (realm для Basic, issuer для Bearer).
Ловушки семантической корректности HTTP
HTTP-механика — логика повторных попыток браузера, кэширование CDN, переписывание прокси — зависит от правильных статус-кодов и заголовков. Распространённые ошибки, вызывающие баги в продакшне:
Неправильные статус-коды:
200 OKдля тела с ошибкой{"error": "not found"}— CDN кэширует 200, логика повторных попыток прокси не срабатывает, консоль браузера не показывает ошибку.200 OKс{ "success": false }— ломает circuit breaker’ы и health check’и.301 Moved Permanentlyдля временного редиректа — браузеры кэшируют 301 навсегда; откат требует очистки кэша браузера.
Ошибки заголовка Vary:
- Отсутствие
Vary: Accept-Encodingдля сжатых ответов — кэш может отдать тело в Brotli клиенту, объявившему толькоAccept-Encoding: gzip, что вызывает искажённый контент. - Отсутствие
Vary: Authorizationдля авторизационно-дифференцированных кэшируемых ответов — CDN отдаёт приватные данные одного пользователя другому.Cache-Control: privateпредотвращает это на уровне CDN, ноVary: Authorization— правильный сигнал. - Слишком широкий
Vary: Cookie— вызывает промах кэша при каждом запросе, так как куки различаются у каждого пользователя; полностью уничтожает кэширование для аутентифицированных пользователей.
Cache-Control: private vs Vary: Authorization: используйте Cache-Control: private для пользовательских данных, которые не должны разделяться через CDN (и добавьте no-store для конфиденциальных). Vary: Authorization говорит разделяемым кэшам хранить отдельные варианты на значение заголовка Authorization — правильно для API-ответов, различающихся по токену, но иначе кэшируемых (например, пользовательские конфигурации).
Auth endpoints, возвращающие 403 вместо 401: 401 Unauthorized означает “сначала аутентифицируйтесь”; 403 Forbidden означает “аутентифицирован, но не разрешено”. Браузеры и API-клиенты обрабатывают их по-разному — 401 запускает запросы учётных данных или потоки обновления токенов; 403 не должен.
CDN отдаёт устаревшие пользовательские API-данные не тем пользователям. Отладьте конфигурацию кэширования.
Бэкенд реального времени мультиплеерной игры обслуживает ~100k конкурентных соединений, преимущественно мобильных клиентов в сотовой сети. Выберите стек протоколов.
Какой RFC объявляет устаревшей схему приоритетов на основе деревьев HTTP/2 и определяет более простой Priority-заголовок на основе срочности?
Спроектируйте протокольный слой для глобального SaaS API с 10k req/s из 50+ стран — смесь REST + WebSocket-style реального времени, с приоритетом мобильных.
- Средний RTT пользователя до вашего edge: 30–200 мс.
- Ожидаются потеристые сети (мобильная связь, спутник, гостиничный Wi-Fi).
- Обратная совместимость с curl, fetch() и gRPC-Web клиентами.
- Аутентификация через bearer-токены; конфиденциальные endpoint'ы не должны нигде кэшироваться.
- Обслуживать все три HTTP-версии; ALPN и Alt-Svc управляют выбором.
- WebTransport для реального времени на h3, WebSocket-h2 как fallback.
- Idempotency-Key на POST для безопасных повторных попыток на потеристых сетях.
- Cache-Control: no-store для конфиденциальных endpoint'ов; max-age + ETag для публичных.
- Мониторить скорость h3-fallback по ASN как сигнал здоровья сети.
- Bearer-токены только в заголовке Authorization — никогда в query string.
- 01Почему дерево приоритетных зависимостей HTTP/2 провалилось и чем RFC 9218 его заменил?
- 02В чём разница между WebTransport и WebSocket?
- 03Назовите три семантические ошибки HTTP, вызывающие баги кэширования CDN в продакшне.
RFC 9218 заменил сложные деревья приоритетных зависимостей HTTP/2 двухпольным сигналом: urgency (u=0–7, меньше = важнее) и incremental (i, частичный стриминг данных между работой с более высоким приоритетом). Все крупные браузеры и CDN поддерживают его по состоянию на 2026. MASQUE (CONNECT-UDP, CONNECT-IP) туннелирует произвольный трафик через HTTP/3 — используется в iCloud Private Relay. QUIC DATAGRAM frames (RFC 9221) несут ненадёжные зашифрованные полезные нагрузки внутри QUIC-соединения; WebTransport предоставляет браузерному JavaScript и надёжные потоки, и ненадёжные датаграммы. Токены аутентификации принадлежат заголовку Authorization — никогда в URL, которые утекают через Referer и логи доступа. Семантическая корректность статус-кодов, заголовков Vary и области Cache-Control определяет корректное поведение кэширования CDN и прокси; ошибки вызывают утечки безопасности и баги устаревших данных в масштабе.
встречается в5
- MVCC: как Postgres раздаёт согласованные снимкиjunior
- Акт 7 в глубину: шардинг, co-location и семиуровневый каскад трейдоффовmiddle
- Наблюдаемость, антипаттерны и производственный триажsenior
- Raft в реальном мире: partition, медленный диск и клиентская маршрутизацияmiddle
- Raft в production: membership change, Multi-Raft и observabilitysenior