Суть Читай реальные HTTP-заголовки, curl-трейс и gRPC-обмен; предсказывай поведение и выбирай фикс с наибольшим рычагом, который senior-инженер сделает первым.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min
Дампы трафика и заголовки ответов — это место, где HTTP-проблемы реально диагностируются. Прочитай обмен, предскажи, что сделает браузер, CDN или QUIC-стек, затем выбери фикс, к которому senior-инженер тянется первым.
Цель
Отработай цикл, который ты запускаешь в каждом HTTP-инциденте: прочитай заголовки и трейс, предскажи поведение на уровне протокола и потянись за структурным фиксом раньше, чем что-либо тюнить.
Сервер рекламирует h3 через Alt-Svc, но хендшейк HTTP/3 фейлится. В чём дело и какой первый фикс?
Heads-up QUIC использует тот же TLS-сертификат, что и TCP-листенер на 443; отдельного QUIC-порта для покрытия нет. Заголовок x-quic-version: draft-29 показывает реальную причину — устаревший драфт QUIC.
Heads-up max-age лишь управляет тем, как долго клиент помнит h3-подсказку; он не может вызвать protocol violation в хендшейке. Дефект — реализация на draft-29.
Heads-up HTTP/2 уже сработал в первом вызове. Явное 'protocol violation: invalid initial packet' — это реальное несовпадение версий QUIC, а не вопрос флага curl.
Сниппет 2 — закэшированный профиль пользователя
GET /api/user/profile HTTP/2authorization: Bearer eyJ...userAHTTP/2 200 OKcontent-type: application/jsoncache-control: max-age=300{"id":"userA","email":"a@example.com"}
Викторина
Completed
Пользователи время от времени видят чужие профили. Читая только эти заголовки, какой баг и верный фикс?
Heads-up Потоки HTTP/2 никогда не перекрещивают тела запросов между соединениями или пользователями. Утечка — это баг семантики кэширования: пер-пользовательский ответ помечен публично кэшируемым.
Heads-up Токены принадлежат заголовку Authorization именно потому, что URL утекают через Referer и логи доступа. Баг — отсутствие private/Vary на ответе, а не расположение токена.
Heads-up Короткий TTL не смешивает пользователей; любой TTL на публично кэшируемом пер-пользовательском ответе утекает. Фикс — сузить кэш (private/no-store), а не менять max-age.
Сниппет 3 — ответ gRPC
HTTP/2 200 OKcontent-type: application/grpc(DATA-фреймы: сериализованное protobuf-сообщение)(хвостовой HEADERS-фрейм)grpc-status: 5grpc-message: user not found
Викторина
Completed
HTTP-статус 200, но grpc-status 5 (NOT_FOUND). Почему результат в трейлере и что ломается, если браузер вызовет это напрямую?
Heads-up По дизайну gRPC держит HTTP-статус на 200 и сигнализирует исход RPC в трейлерах grpc-status; это корректно, а не баг. Расположение трейлера отражает тайминг конца потока.
Heads-up Трейлеры — про тайминг метаданных конца потока, а не про CORS. Браузеры просто не отдают HTTP-трейлеры в JS, отсюда gRPC-Web.
Heads-up HTTP/2 поддерживает хвостовые HEADERS-фреймы, и gRPC на них опирается. Тело держит protobuf-сообщение; статус законно попадает в трейлер.
Оба запроса приходят одновременно по HTTP/3. Читая заголовки Priority из RFC 9218, какой сервер отправит первым и каково правило?
Heads-up RFC 9218 инвертирует эту интуицию: меньшее u срочнее. u=1 (CSS) обходит u=5 (изображение), поэтому CSS отправляется первым.
Heads-up Это и был сбойный режим, который починил RFC 9218. С заголовками Priority, уважаемыми современными серверами и CDN, сервер переупорядочивает DATA-фреймы по срочности.
Heads-up Multiplexing допускает чередование, но приоритеты говорят серверу, как взвесить полосу DATA-фреймов — в пользу потока с меньшим значением urgency (более срочного).
Итог
Каждый HTTP-инцидент читается в заголовках и трейсах: подсказка Alt-Svc h3 при QUIC-стеке на драфте жжёт RTT на каждого клиента; пер-пользовательский ответ без private/no-store и Vary утекает через общий кэш; реальный исход gRPC живёт в хвостовом HEADERS-фрейме (200 на уровне HTTP) и требует gRPC-Web для браузеров; а urgency в RFC 9218 инвертирован — меньшее u срочнее. Читай трафик, предсказывай поведение протокола, затем применяй структурный фикс.