HTTP/2 і HTTP/3: еволюція протоколу
Зміст
Версія протоколу — те, що тестувальник згадує останнім. Тест падає «через раз» на мобільній мережі, сторінка завмирає вся одразу, домен- у старому проєкті нічого не прискорює, а за питанням «HTTP/2 усунув HOL-блокування — правда?» на співбесіді ховається пастка. Спільне тут одне: симптом породжує транспорт, а шукають його в застосунку.
Ця глава — повний виклад теми на сайті, інші глави посилаються сюди по механіку версій. Мета — розводити два шари: що змінюється між HTTP/1.1, HTTP/2 і HTTP/3 (і що не змінюється взагалі) та які симптоми законно пояснювати версією, а які ні.
Що змінює версія протоколу, а що ні
HTTP/2 — не нова семантика HTTP, а оптимізоване подання тієї самої семантики: методи, статус-коди й заголовки лишаються ті самі, змінюється спосіб, у який вони їдуть по зʼєднанню. Виграш дають дві речі: стиснення полів і кілька одночасних обмінів на одному зʼєднанні. Чинна специфікація — RFC 9113, вона скасовує RFC 7540 і RFC 8740.
HTTP/3 — те саме відображення семантики HTTP на новий транспорт: замість TCP під ним працює QUIC. Дизайн успадковано від HTTP/2, але життєвий цикл потоків, контроль потоку, шифрування й автентифікацію сторін делеговано транспорту.
Мапа специфікацій після ревізії 2022 року показує це формально: семантика (RFC 9110) і кешування (RFC 9111) спільні для всіх версій, версійні лише RFC 9112 (HTTP/1.1), RFC 9113 (HTTP/2) і RFC 9114 (HTTP/3). MDN зводить різницю HTTP/2 з HTTP/1.1 до трьох пунктів: бінарний замість текстового (руками не почитаєш і не складеш), мультиплексований, зі стисненням заголовків.
Головний практичний наслідок: переїзд на HTTP/2 чи HTTP/3 не переписує ваші перевірки — на статус, тіло, кукі й заголовки лишаються чинними. Якщо тест зламався «через HTTP/2», підозра має падати на щось конкретне: розмір заголовків, кількість паралельних потоків, поведінку проміжного вузла.
Обмеження HTTP/1.x: чому браузер відкриває шість зʼєднань
Зʼєднання HTTP/1.x серіалізує запити: наступний іде після відповіді на попередній. Саме зʼєднання при цьому постійне — канал перевикористовується й економить TCP. Але один канал — одна черга, тож єдиний спосіб працювати паралельно — відкрити кілька зʼєднань до домену. Колишній дефолт — 2–3, нинішній поширений — шість на домен; перевищувати ризиковано, бо на боці сервера це може зачепити захист від DoS.
Пастка
Шість — це поточна практика браузерів, а не норма протоколу: у RFC такого числа немає. Подавати його треба саме так: «браузери зазвичай відкривають до шести зʼєднань на домен», а не «протокол дозволяє шість».
Звідси домен-шардінг (domain sharding): розкласти статику по піддоменах www1, www2, www3, які резолвляться в той самий сервер, — і браузер відкриє по шість зʼєднань до кожного, у прикладі MDN 18 замість 6. MDN уже позначає техніку застарілою: на HTTP/2 вона не просто зайва, а шкідлива для продуктивності, і більшість реалізацій «розшивають» шардінг назад обʼєднанням зʼєднань (connection coalescing).
На HTTP/2 картина протилежна: специфікація каже, що клієнт не повинен відкривати більш ніж одне зʼєднання на пару «хост+порт». Модальність тут важлива: SHOULD NOT — наполеглива рекомендація з винятками (заміна наявного зʼєднання, різні значення SNI, різні клієнтські сертифікати), а не заборона. Задум однозначний: паралельність дають потоки, а не зʼєднання.
Ще один спадок тієї самої проблеми — (pipelining). Сучасні браузери його не вмикають: він все одно страждає на , а надсилати пайплайном можна лише (GET, HEAD, OPTIONS, TRACE, PUT, DELETE) — при збої вміст пайплайна доводиться повторювати.
Скільки зʼєднань браузер підняв насправді — видно в колонці Connection ID панелі Network. Звідси й гіпотеза з терміном придатності: «сторінка гальмує, бо забагато дрібних файлів» правдоподібна на HTTP/1.1 і неправдоподібна на HTTP/2, а піддомени «для швидкості» в старому проєкті — кандидат на видалення, а не на перевірку.
HOL-блокування: два рівні, а не один
HOL-блокування (head-of-line blocking) — ситуація, коли перший елемент черги, який не може завершитися, тримає всі наступні, навіть якщо ті вже готові. У вебі це поняття живе на двох різних рівнях, і кожна версія HTTP розвʼязує рівно один із них. Плутати рівні — головна помилка в темі «HTTP/2 усе полагодив».
Рівень 1, прикладний. У HTTP/1.0 на одному TCP-зʼєднанні міг «висіти» лише один запит одночасно. у HTTP/1.1 вирішив паралельність частково й лишила блокування на прикладному рівні — саме тому клієнти відкривають кілька зʼєднань. Обхід має ціну: TCP не ділить контроль перевантаження між зʼєднаннями, тож зайві зʼєднання шкодять і йому, і ефективності мережі. Друга вада того самого рівня — повторювані багатослівні заголовки: вони не лише жеруть трафік, а й швидко заповнюють початкове вікно перевантаження TCP, даючи надмірну на нових зʼєднаннях. Додає й текстова природа HTTP/1.1: розділення повідомлень пробільними символами читабельне для людини, але «веде до складності розбору й надмірної терпимості до відхилень у поведінці» — два можуть по-різному зрозуміти той самий кривий запит.
Рівень 2, транспортний. HTTP/2 прибирає блокування на прикладному рівні: потоки майже незалежні, тож заблокований запит не спиняє інші. Але специфікація HTTP/2 прямо зазначає, що блокування на рівні TCP цей протокол не усуває. Механіка: паралельність потоків HTTP/2 не видна механізмам відновлення втрат TCP, тому втрачений або переставлений пакет спиняє всі активні — навіть ті, чиїх даних у пакеті не було. На дротовому каналі це непомітно, на мобільній мережі — дуже.
Рівень 2 закриває HTTP/3. QUIC гарантує порядок лише всередині потоку й нічого не обіцяє щодо порядку між потоками — тому втрата в одному потоці не гальмує решту: кожна пара «запит-відповідь» займає окремий QUIC-потік. Одне джерело блокування лишається й тут — саме стиснення заголовків: QPACK тому й дає кодувальнику важіль балансувати між ступенем стиснення й блокування, спричиненого стисненням.
Є й неочевидний наслідок «одного зʼєднання замість кількох»: коли паралелізму на рівні TCP уже немає, погана схема пріоритезації здатна зробити HTTP/2 помітно повільнішим за HTTP/1.1.
| Рівень блокування | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Прикладний (черга запитів) | є | немає | немає |
| Транспортний (втрата пакета) | є | є | немає |
| Транспорт | TCP | TCP | QUIC |
Робочих тез для тестувальника звідси дві. «Один повільний запит гальмує всю сторінку» — діагноз, що залежить від версії: на HTTP/1.1 винна черга запитів, на HTTP/2 — втрата пакета в TCP, на HTTP/3 обидва пояснення відпадають. І різниця між HTTP/2 та HTTP/3 найпомітніша саме на мережі з втратами: на ідеальному дротовому каналі втрачати нічого, тож звичайний smoke на офісному Wi-Fi «перевіркою HTTP/3» не є.
HTTP/2 зсередини: кадри, потоки, ліміти
HTTP/2 — протокол прикладного рівня, орієнтований на зʼєднання, який працює поверх TCP; ініціює зʼєднання клієнт.
Базова одиниця обміну — кадр (frame): найменша одиниця обміну в межах зʼєднання, що складається із заголовка і послідовності октетів змінної довжини, структурованої за типом кадру. Запити й відповіді будуються з кадрів HEADERS і DATA, службові функції несуть SETTINGS, WINDOW_UPDATE, PUSH_PROMISE. Поверх кадрів живуть потоки (streams): потік — незалежна двонаправлена послідовність кадрів у межах одного зʼєднання, кожен обмін «запит/відповідь» живе у власному потоці, а цілочисельний ідентифікатор призначає та сторона, що потік ініціює. Одне зʼєднання тримає багато одночасно відкритих потоків, і будь-яка зі сторін перемежовує їхні кадри — це і є мультиплексування (multiplexing).
Паралелізм не безмежний і не таємний: його обмежує параметр SETTINGS_MAX_CONCURRENT_STREAMS, який кожна сторона оголошує для свого партнера — клієнт задає ліміт для сервера, сервер для клієнта. Тому коли e2e- чи навантажувальний сценарій упирається в стелю паралельності, дивляться на оголошений сервером ліміт, а не гадають про браузер. Тримається все це на контролі потоку (не надсилати більше, ніж отримувач здатен обробити) і на пріоритезації.
Заголовки стискаються, бо містять багато надлишкових даних; у типовому випадку це дозволяє вмістити багато запитів в один пакет. Алгоритм визначено окремою специфікацією (HPACK): стиснений блок полів їде в кадрі HEADERS (або PUSH_PROMISE), а якщо не влазить — у наступних кадрах CONTINUATION.
Пастка
Блок полів передається суцільною послідовністю кадрів: усередину не можна вклинити кадр іншого типу чи іншого потоку. Це єдиний виняток із загального перемежовування — і саме він пояснює, чому роздуті кукі й гігантські токени на HTTP/2 коштують дорожче, ніж здається: поки блок їде, зʼєднання зайняте лише ним.
Зʼєднання HTTP/2 постійні: їх тримають відкритими, доки не стане зрозуміло, що спілкування з сервером більше не потрібне. Коректне закриття починається з кадру GOAWAY — щоб обидві сторони знали, які кадри вже оброблено.
Сервер-пуш (server push) — необовʼязковий режим, у якому сервер спекулятивно надсилає дані, що, за його прогнозом, знадобляться клієнту: він синтезує запит і шле його кадром PUSH_PROMISE. Чому це рідко окупається, фіксує сама специфікація: сервер має правильно вгадати додаткові запити з урахуванням , узгодження вмісту й поведінки користувача, а помилка прогнозу коштує зайвих даних у мережі й може погіршити продуктивність. Ключове слово — кешування: сервер не знає, що вже лежить у браузера. Клієнт може вимкнути пуш параметром SETTINGS_ENABLE_PUSH = 0, і домовленість діє окремо на кожному «стрибку».
Повчальна й історія з пріоритетами: схему сигналізації з RFC 7540 визнано невдалою і в RFC 9113 оголошено застарілою.
Як клієнт і сервер домовляються про версію
Версію HTTP не «вмикають» — про неї домовляються на старті зʼєднання. Способів три: узгодження через захищене зʼєднання з TLS і ALPN (Application-Layer Protocol Negotiation); апгрейд відкритого зʼєднання без попереднього знання; старт відкритого HTTP/2 із попереднім знанням. Рекомендований перший: протокол узгоджують усередині рукостискання TLS, без додаткових .
Далі — місце хибного висновку зі специфікації. Стандарт HTTP/2 TLS не вимагає: незашифроване зʼєднання технічно можливе, але зі зайвою складністю — HTTP/1.x і HTTP/2 живуть на тому самому порту 80, тож версію доводиться узгоджувати механізмом Upgrade (токен h2c, відповідь 101 Switching Protocols). Вимагають браузери: усі популярні взялися підтримувати HTTP/2 поверх TLS, а частина — зокрема Firefox і Google Chrome — заявила, що вмикатиме його лише поверх TLS. Звідси «TLS з ALPN — де-факто вимога для HTTP/2 в браузері»; база сумісності додає умову з боку сервера: браузер підніме HTTP/2, тільки якщо сервер уміє узгоджувати протокол через ALPN. Практичний наслідок: локальний стенд на http:// завжди піде по HTTP/1.1, і дефект на це не заводять.
З HTTP/3 механізм інший. Клієнт не може просто «спробувати HTTP/3» — він спершу має дізнатися, що точка HTTP/3 узагалі є. оголошує її заголовком відповіді Alt-Svc (або кадром ALTSVC у HTTP/2) з токеном h3:
HTTP/2 200
content-type: text/html; charset=utf-8
alt-svc: h3=":50781"
Отримавши такий запис, клієнт може спробувати підняти QUIC-зʼєднання; сам вибір HTTP/3 позначається токеном ALPN h3 під час рукостискання, у якому QUIC заразом узгоджує транспортні параметри. Якщо мережа ріже UDP, зʼєднання не встановиться, і клієнтові рекомендовано (SHOULD) спробувати версії HTTP поверх TCP — сайт працюватиме, просто тихо, по HTTP/2.
Звідси спостереження, що рятують від хибних дефектів. Перше завантаження часто йде не по HTTP/3: спершу приходить Alt-Svc, і лише наступні запити браузер пробує по QUIC. Різні протоколи в одному сеансі — теж норма: на одній сторінці частина запитів може йти h2, частина h3, частина http/1.1, залежно від того, з ким і як домовилися. А ще версію здатен «зняти» проміжний вузол: керування зʼєднанням діє між двома сусідніми вузлами, а не наскрізно, тож браузер і сервер цілком можуть бачити різне.
HTTP/3 і QUIC: що дає новий транспорт
QUIC — захищений транспортний протокол загального призначення, орієнтований на зʼєднання; RFC 9000 визначає його першу версію. Він дає три речі, яких не було в стеку TCP+TLS: потоки з власним контролем потоку, низьколатентне встановлення зʼєднання і міграцію між мережевими шляхами.
Транспорт і шифрування. QUIC-пакети їдуть у UDP-датаграмах; автентифікується весь пакет, а шифрується максимум можливого. HTTP/3 працює поверх QUIC версії 1, а той використовує TLS 1.3 або новішу як протокол рукостискання — незашифрованого HTTP/3 не буває. Більше того, схема http:// привʼязана до здатності приймати TCP-зʼєднання, а HTTP/3 TCP не використовує, тож прямого доступу по HTTP/3 до http://-ресурсу не існує взагалі. Сервер при цьому може віддавати HTTP/3 на будь-якому UDP-порту — «а чому не 443» дефектом не є.
Швидший старт і 0-RTT. QUIC зливає криптографічне й транспортне рукостискання в одне — звідси менша затримка на старті. Для повторних зʼєднань є режим 0-RTT: клієнт шле прикладні дані ще до відповіді сервера.
Пастка
Ціну 0-RTT специфікація називає прямо: він не захищає від replay-. Не ідемпотентні запити — оплату, створення замовлення — в 0-RTT слати не можна, і в тест-плані це окремий рядок: перевіряють не таймінги, а те, які операції застосунок дозволяє в ранній фазі зʼєднання.
Потоки. Кожна пара «запит-відповідь» займає один QUIC-потік, і мультиплексування тут — робота транспорту, а не прикладного рівня: HTTP не потребує окремого мультиплексування поверх QUIC. Усередині потоку одиниця обміну — кадр (HEADERS, DATA тощо), а кадри рівня зʼєднання їдуть окремим керівним потоком. Специфікація радить дозволяти щонайменше 100 одночасних потоків-запитів, тож «мало паралельності» на HTTP/3-стенді — привід дивитися в конфігурацію, а не в протокол. Стиснення довелося замінити: HPACK вимагає впорядкованої доставки, якої QUIC не дає, тому заголовки стискає QPACK, а стан його таблиці тримають на окремих однонаправлених потоках. Сервер-пуш формально лишився, але ініціативу віддано клієнту ще жорсткіше: сервер не може нічого пушити, доки клієнт не надішле кадр MAX_PUSH_ID.
Міграція зʼєднання. Зʼєднання впізнається за ідентифікатором зʼєднання (connection ID), а не за парою «IP+порт», тому переживає зміну мережевого шляху чи переприсвоєння адрес у NAT — на TCP воно б розірвалося. Обмеження варто знати: ініціювати міграцію може лише клієнт і лише після підтвердження рукостискання, а зміну адреси партнера треба підтвердити валідацією шляху. Тому «активна сесія переживає перехід із Wi-Fi у мобільну мережу» — законний тест-кейс, а перемикання мережі до підтвердження рукостискання міграцією не є взагалі: до цього моменту специфікація її забороняє.
Що з версії видно у вкладці Network
Питання «по якій версії пішов цей запит» має точну відповідь. У панелі Network є колонка Protocol: вона показує протокол запиту — наприклад h2 для HTTP/2 і h3 для HTTP/3. Пастка в тому, що типово її не видно: частина колонок показана за замовчуванням, решта ні, і вмикають їх правою кнопкою по шапці таблиці. Поруч варті уваги ще дві: Connection ID — ідентифікатор зʼєднання запиту (на HTTP/1.1 чекайте кілька значень на домен, на HTTP/2 — одне на «хост+порт»), і Remote address — віддалена IP-адреса й порт, чим зручно доводити, що піддомени резолвляться в той самий сервер. Під конкретний заголовок відповіді можна додати власну колонку через Response Headers > Manage Header Columns.
Механіку панелі розбирає глава «DevTools: вкладка Network і дебаг»; тут важливий один висновок: версію протоколу й кількість зʼєднань не вгадують — їх вмикають. І спостереження з панелі має продовження в автотесті: побачили, який запит завершує дію, — чекайте саме на нього, а не на фіксовану паузу.
// чекаємо на конкретну відповідь, а не на секунди
await page.waitForResponse((r) => r.url().includes('/api/orders') && r.ok());
Поширеність версій: цифри лише з датою
HTTP/2 стандартизували у травні 2015; за даними, на які посилається MDN, його вживання досягло піку в січні 2022 — 46,9 % усіх сайтів. Найшвидше переходили високонавантажені сайти, заради економії на передачі даних. HTTP/3 станом на жовтень 2022 використовували 26 % усіх сайтів, і його підтримує більшість основних браузерів — зокрема Chromium і його похідні (Chrome, Edge) та Firefox.
Пастка
Обидві цифри — частка сайтів, а не частка трафіку: це різні метрики, і джерела зі статистикою трафіку тут немає. «46,9 % сайтів у січні 2022 за даними, на які посилається MDN» — коректно; «більшість трафіку — HTTP/2» — ні.
Цікавіша за числа причина поширення: HTTP/2 не вимагав змін у сайтах і застосунках — досить було свіжого сервера й свіжого браузера. Для тестувальника в цього неприємний бік: перехід на нову версію протоколу — не реліз застосунку, і про нього можуть просто не сказати. Інфраструктура оновилася, код не змінився, а тести побачили іншу поведінку мережі. Тому версію варто фіксувати в описі середовища поруч із версією браузера.
Типові помилки
- Виглядає як «HTTP/2 усунув HOL-блокування», а насправді усунув на прикладному рівні, а на рівні TCP — ні, і специфікація каже це прямо.
- Виглядає як «перейшли на HTTP/2, отже швидше», а насправді за поганої пріоритезації буває повільніше, ніж на HTTP/1.1: паралелізму на рівні TCP уже немає.
- Виглядає як «HTTP/2 не вмикається — баг конфігурації», а насправді стенд відкривається по
http://, а браузери вмикають HTTP/2 лише поверх TLS з ALPN. - Виглядає як «HTTP/3 не працює, перший запит пішов по h2», а насправді так і має бути: спершу приходить
Alt-Svc, і лише наступні запити йдуть по QUIC. - Виглядає як «шість зʼєднань — норма протоколу», а насправді це практика браузерів; у RFC такого числа немає.
- Виглядає як «розкладемо статику по піддоменах — буде паралельніше», а насправді на HTTP/2 шардінг шкідливий, а реалізації ще й обʼєднують зʼєднання назад.
- Виглядає як «0-RTT — це просто швидше», а насправді це обмін гарантій на швидкість: захисту від
replay-атак там немає. - Виглядає як «сайт працює по HTTP/3», а насправді версія — властивість запиту: в одному сеансі законно співіснують
h3,h2іhttp/1.1.
Підсумок
- Версія протоколу міняє подання, а не семантику: методи, й заголовки ті самі, тому переїзд на HTTP/2 чи HTTP/3 не переписує перевірки.
- HOL-блокування живе на двох рівнях: прикладний закриває HTTP/2, транспортний — лише HTTP/3 поверх QUIC.
- Паралельність на HTTP/1.x купують зʼєднаннями (звідси шість на домен і домен-шардінг), на HTTP/2 — потоками в одному зʼєднанні з оголошеним лімітом
SETTINGS_MAX_CONCURRENT_STREAMS. - QUIC дає те, чого не було в TCP+TLS: незалежні потоки, злите рукостискання з обовʼязковим TLS 1.3 і міграцію зʼєднання за його ідентифікатором — а ціна 0-RTT називається окремо.
- Версію не припускають: її вмикають колонкою
Protocol, а різниця HTTP/2 проти HTTP/3 стає видимою лише на мережі з втратами або при зміні мережі.
Можливі питання
- «Чим HTTP/2 відрізняється від HTTP/1.1?» Перевіряють, чи не почнете з «він швидший». Сильна відповідь розводить семантику й подання, а тоді називає механізм: бінарні кадри, потоки в одному зʼєднанні, стиснення полів.
- «HTTP/2 прибрав HOL-блокування — правда?» Питання про акуратність: очікують «на прикладному рівні так, на рівні TCP ні» з механікою втраченого пакета.
- «Чому на HTTP/2 не потрібен домен-шардінг?» Дивляться, чи знаєте рекомендацію одного зʼєднання на «хост+порт» — і чи не перетворите
SHOULD NOTна заборону. - «Що дає QUIC понад TCP?» Очікують три пункти зі специфікації — потоки з власним контролем потоку, низьколатентне встановлення, міграція — і згадку про обовʼязковий TLS 1.3.
- «Як браузер дізнається, що є HTTP/3?» Механізм оголошення:
Alt-Svcз токеномh3, далі ALPN у рукостисканні, і на TCP-версії, якщо UDP заблоковано. - «Як перевірити те, чим HTTP/3 справді відрізняється від HTTP/2?» Слухають, чи не запропонуєте smoke на офісному Wi-Fi. Очікують втрати пакетів і зміну мережі під час активної сесії.
Джерела
Що змінює версія протоколу, а що ні
- RFC 9113 — HTTP/2 — оптимізоване подання тієї самої семантики, два джерела виграшу, скасування RFC 7540 і RFC 8740.
- RFC 9114 — HTTP/3 — та сама семантика поверх QUIC і те, що делеговано транспорту.
- RFC 9000 — QUIC: A UDP-Based Multiplexed and Secure Transport — QUIC як транспорт, на який відображено HTTP/3.
- MDN — Evolution of HTTP — мапа специфікацій 9110–9114 і три відмінності HTTP/2 від HTTP/1.1.
Обмеження HTTP/1.x: чому браузер відкриває шість зʼєднань
- MDN — Connection management in HTTP/1.x — серіалізація запитів, постійні зʼєднання, 2–3 проти шести, домен-шардінг і його застарілість, вимкнений пайплайнінг.
- RFC 9113 — HTTP/2 — рекомендація одного зʼєднання на «хост+порт» і її модальність.
- Chrome DevTools — Network features reference — колонка
Connection IDяк спосіб побачити реальну кількість зʼєднань.
HOL-блокування: два рівні, а не один
- RFC 9113 — HTTP/2 — блокування на прикладному рівні в HTTP/1.x, застереження про TCP, багатослівні заголовки й вікно перевантаження, ризик гіршої за HTTP/1.1 продуктивності.
- RFC 9114 — HTTP/3 — ціна кількох TCP-зʼєднань, зупинка всіх транзакцій при втраті пакета, текстовий формат HTTP/1.1 і складність розбору, залишкове блокування через стиснення.
- RFC 9000 — QUIC: A UDP-Based Multiplexed and Secure Transport — порядок гарантовано лише всередині потоку.
HTTP/2 зсередини: кадри, потоки, ліміти
- RFC 9113 — HTTP/2 — кадри й потоки, мультиплексування,
SETTINGS_MAX_CONCURRENT_STREAMSдля партнера, HPACK і суцільний блок полів,GOAWAY, сервер-пуш та його межі, застаріла схема пріоритетів.
Як клієнт і сервер домовляються про версію
- High Performance Browser Networking — HTTP/2 — три способи узгодження версії, TLS з ALPN як рекомендований і де-факто обовʼязковий у браузері,
h2cчерезUpgrade. - caniuse — HTTP/2 protocol (features-json) — HTTP/2 у браузерах лише поверх TLS і умова ALPN на боці сервера.
- RFC 9114 — HTTP/3 — оголошення через
Alt-Svcз токеномh3, ALPN-токен вибору, рекомендація фолбеку на версії поверх TCP. - RFC 9000 — QUIC: A UDP-Based Multiplexed and Secure Transport — узгодження прикладного протоколу й транспортних параметрів усередині рукостискання QUIC.
- Chrome DevTools — Network features reference — колонка
Protocolпоказує версію порядково, тож різні протоколи в одному сеансі видно одразу. - MDN — Connection management in HTTP/1.x — керування зʼєднанням діє між сусідніми вузлами, а не наскрізно, тож проміжний вузол здатен «зняти» версію.
HTTP/3 і QUIC: що дає новий транспорт
- RFC 9114 — HTTP/3 — обовʼязковий TLS 1.3 під HTTP/3, схема
http://і TCP, будь-який UDP-порт, потік на пару «запит-відповідь», мультиплексування як робота транспорту, порада про 100 потоків, QPACK,MAX_PUSH_ID. - RFC 9000 — QUIC: A UDP-Based Multiplexed and Secure Transport — три властивості QUIC понад TCP, UDP-датаграми й шифрування, злите рукостискання, 0-RTT і
replay-атаки, ідентифікатор зʼєднання та міграція.
Що з версії видно у вкладці Network
- Chrome DevTools — Network features reference — колонки
Protocol,Connection ID,Remote address, вмикання колонок правою кнопкою іManage Header Columns. - Playwright — Network — очікування конкретного мережевого запиту в тесті замість паузи.
Поширеність версій: цифри лише з датою
- MDN — Evolution of HTTP — дати й частки сайтів для HTTP/2 і HTTP/3, підтримка браузерами, нульова ціна переходу для застосунку.
Чим HTTP/2 відрізняється від HTTP/1.1?
Найточніша рамка для відповіді така: змінилося подання, а не сенс. Той самий набір методів, і заголовків їде по зʼєднанню інакше — і саме в цьому «інакше» весь виграш. MDN зводить різницю до трьох пунктів: формат став бінарним замість текстового, обмін став мультиплексованим, а поля заголовків почали стискатися. Бінарність означає, що запит більше не почитаєш і не складеш руками — потрібен інструмент, який уміє розібрати кадри. Мультиплексування означає, що кілька обмінів живуть в одному зʼєднанні паралельно, а не по черзі. Стиснення бʼє по давній ваді HTTP/1.1 — повторюваних багатослівних заголовках, які їхали в кожному запиті. Слабка відповідь на це питання починається зі слова «швидший»: інтервʼюер саме її й чекає, щоб уточнити, за рахунок чого.
Чи доведеться переписувати автотести після переїзду на HTTP/2 або HTTP/3?
Ні, і це основний практичний висновок теми. Семантику протоколу після ревізії специфікацій винесли в окремий документ, спільний для всіх версій, — версійні лише документи про подання. Тобто на статус-код, тіло, кукі й заголовки лишаються чинними без жодної правки. Якщо тест таки зламався одночасно з переїздом, «винен HTTP/2» — не діагноз, а гіпотеза, і її треба звузити до чогось конкретного: розміру заголовків, стелі паралельних потоків, поведінки проміжного вузла. Окремо варто памʼятати організаційний бік: оновлення протоколу зазвичай не є релізом застосунку, тож команду про нього можуть просто не попередити. Саме тому версію протоколу фіксують в описі середовища поруч із версією браузера, а цифри поширеності подають обережно — вони існують як частка сайтів на конкретну дату, а не як частка трафіку.
Чому браузер відкриває кілька зʼєднань до одного домену і звідки взялося число шість?
Зʼєднання HTTP/1.x пропускає запити строго послідовно: наступний стартує після того, як приїхала відповідь на попередній. Саме зʼєднання при цьому лишається живим і перевикористовується, економлячи , але черга в ньому одна. Єдиний спосіб отримати паралельність — підняти кілька зʼєднань до того самого домену: колись їх було два-три, зараз поширений дефолт — шість. Ключова обережність у формулюванні: шістку задають самі браузери, а не документ, — жодна специфікація цього числа не називає. І задирати його безкарно не вийде — на боці сервера велика кількість одночасних зʼєднань може виглядати як й зачепити захист від в обслуговуванні.
Що таке домен-шардінг і чому його прибирають?
Це трюк епохи HTTP/1.1: статику розкладають по піддоменах на кшталт www1, www2, www3, які насправді ведуть на той самий сервер, — і браузер відкриває свою пачку зʼєднань до кожного з них замість однієї на всіх. У прикладі MDN так виходить 18 паралельних зʼєднань замість шести. Сьогодні техніку позначено застарілою, і на HTTP/2 вона не просто безкорисна, а шкідлива для продуктивності: паралельність там дають потоки в одному зʼєднанні, а розсипані піддомени цю модель ламають. Більшість реалізацій ще й «розшивають» назад, обʼєднуючи зʼєднання (connection coalescing), тож ефект від піддоменів може виявитися нульовим. Для тестувальника звідси конкретна дія: піддомени «для швидкості» у старому проєкті — кандидат на видалення, а не на перевірку, і довести, що вони ведуть в одне місце, найлегше колонкою Remote address.
Скільки зʼєднань на «хост+порт» дозволяє HTTP/2?
Стандарт формулює це як наполегливу пораду: піднімати більше одного зʼєднання до тієї самої пари «хост+порт» клієнтові не варто. Модальність тут принципова — за нею стоїть SHOULD NOT, тобто рекомендація з винятками, а не заборона. Винятки названо прямо: заміна наявного зʼєднання, різні значення SNI, різні клієнтські сертифікати. Задум при цьому однозначний — паралельність купують потоками, а не новими зʼєднаннями. На співбесіді на цьому місці перевіряють акуратність: людина, яка перетворює SHOULD NOT на «протокол забороняє», зазвичай так само вільно поводиться і з рештою вимог.
Що таке HOL-блокування (head-of-line blocking)?
Це коли незавершений елемент на початку черги стопорить усе, що стоїть за ним, — включно з тим, що давно готове їхати. У вебі поняття живе одразу на двох рівнях, і саме їх плутають найчастіше. Прикладний рівень — це черга запитів усередині одного HTTP-зʼєднання: поки не приїхала відповідь на перший, решта чекає. Транспортний рівень — це вже властивість TCP: втрачений або переставлений пакет зупиняє доставку всього, що йде після нього. Кожна нова версія HTTP закриває рівно один із цих рівнів, і відповідь «HTTP/2 усе полагодив» ловить кандидата саме тут.
«HTTP/2 усунув HOL-блокування» — це правда?
Наполовину, і це наполовину треба назвати вголос. На прикладному рівні — так: потоки в HTTP/2 майже незалежні, заблокований запит не спиняє сусідів, черги запитів більше немає. Але про рівень TCP специфікація HTTP/2 говорить прямо — цього блокування протокол не усуває. Механізм такий: механізми відновлення втрат у TCP нічого не знають про потоки HTTP/2, для них зʼєднання — один потік байтів, тож втрачений пакет спиняє всі активні обміни, включно з тими, чиїх даних у ньому взагалі не було. Чи побачите ви це, залежить від каналу: там, де втрачати нічого, ефекту практично немає, а на мобільній мережі з втратами він виходить на перший план. Другий рівень закриває вже HTTP/3: упорядкованість QUIC обіцяє тільки в межах окремого потоку, а між потоками не обіцяє нічого, — тож втрата бʼє по одному потоку, а не по всіх одразу.
Чи лишилося щось від HOL-блокування в HTTP/3?
Так, одне джерело — саме стиснення заголовків. Щоб розтиснути блок полів, приймальна сторона має мати відповідний стан таблиці, а він приїжджає окремими потоками; поки потрібного запису немає, розбір чекає. Тому QPACK свідомо дає кодувальнику важіль: можна тиснути сильніше й ризикувати блокуванням або тиснути обережніше й не залежати від ще не доставлених оновлень таблиці. Практично це означає, що фраза «у HTTP/3 HOL-блокування немає взагалі» — неточна, і сильний кандидат сам зробить цю поправку.
Чи може HTTP/2 виявитися повільнішим за HTTP/1.1?
Може, і специфікація це визнає. Логіка така: коли всі обміни зведено в одне зʼєднання, зникає той грубий паралелізм, який раніше давали шість окремих каналів TCP. Далі все залежить від того, наскільки розумно сервер вирішує, чиї кадри відправляти першими. Погана схема пріоритезації здатна поставити критичний ресурс за хвостом другорядних, і сторінка відмальовується помітно пізніше, ніж відмальовувалася б на HTTP/1.1. Історія тут повчальна й на рівні стандарту: схему сигналізації пріоритетів із першої редакції HTTP/2 визнали невдалою і в чинній редакції оголосили застарілою.
Що таке кадр і потік у HTTP/2 і як з них складається мультиплексування?
Кадр — найменша одиниця обміну в межах зʼєднання: заголовок плюс послідовність октетів змінної довжини, структура якої залежить від типу кадру. Типів кадрів кілька, і вони діляться за роллю: корисне навантаження запиту й відповіді везуть HEADERS та DATA, а службу — SETTINGS, WINDOW_UPDATE, PUSH_PROMISE. Потік — незалежна двонаправлена послідовність кадрів усередині одного зʼєднання; кожна пара «запит-відповідь» живе у власному потоці, а цілочисельний ідентифікатор потоку призначає та сторона, яка його ініціює. Мультиплексування — це і є перемежовування кадрів різних потоків в одному зʼєднанні, і робити його може будь-яка зі сторін. Звідси й головна відмінність від HTTP/1.1: паралельність перестала бути кількістю каналів і стала кількістю потоків.
Чим обмежена кількість одночасних потоків і де це дивитися?
Параметром SETTINGS_MAX_CONCURRENT_STREAMS, і в ньому є тонкість, на якій люблять ловити: кожна сторона оголошує цей ліміт для свого партнера, а не для себе. Тобто скільки потоків одночасно дозволено відкривати клієнту — вирішує сервер, і навпаки. Практичний наслідок прямий: коли навантажувальний або великий e2e-сценарій упирається в стелю паралельності, дивляться на значення, оголошене сервером, а не будують здогади про браузер. Поруч працюють ще два механізми, які теж стримують потік даних: контроль потоку (не слати більше, ніж отримувач здатен перетравити) і пріоритезація.
Чому роздуті кукі й великі токени на HTTP/2 коштують дорожче, ніж здається?
Через правило суцільного блоку полів. Стиснені поля везе кадр HEADERS (або PUSH_PROMISE), а хвіст, що не вмістився, доїжджає кадрами CONTINUATION — і розривати цю послідовність нічим стороннім не дозволено. Перемежовування, на якому тримається весь HTTP/2, тут вимикається: доки величезний блок не доїде цілком, зʼєднання зайняте виключно ним, а решта потоків чекає. Тобто кілограмова кукі чи JWT на пів екрана бʼє не тільки по обсягу трафіку, а й по паралельності, заради якої HTTP/2 і вмикали. Для QA це готовий тест-кейс: додали новий заголовок автентифікації — подивіться, наскільки виріс блок і чи не почала сторінка гірше розкладатися.
Що таке сервер-пуш у HTTP/2 і чому він рідко окупається?
Це необовʼязковий режим, у якому сервер сам вирішує, що клієнту зараз знадобиться, синтезує за нього запит і надсилає кадр PUSH_PROMISE, а слідом дані. Причину невдачі фіксує сама специфікація: щоб пуш дав виграш, серверу треба точно передбачити наступні запити, врахувавши і , і узгодження подання, і те, як людина поводитиметься далі, — а промах прогнозу означає марно передані дані й може обернутися просідом продуктивності. Найслабша ланка тут — кешування: сервер просто не знає, що вже лежить у браузера, тож регулярно пушить те, що клієнт і так має. Клієнт може відмовитися від режиму, виставивши SETTINGS_ENABLE_PUSH = 0, і ця домовленість діє окремо на кожному «стрибку» між сусідніми вузлами, а не наскрізно. У HTTP/3 режим нікуди не зник, але останнє слово за клієнтом стало ще вагомішим: доки від нього не приїде кадр MAX_PUSH_ID, серверу пушити не дозволено взагалі.
Чи вимагає HTTP/2 шифрування?
Стандарт — ні, браузери — так, і в цьому вся плутанина. Технічно незашифроване зʼєднання HTTP/2 можливе, просто зі зайвою складністю: HTTP/1.x і HTTP/2 ділять порт 80, тож версію доводиться узгоджувати механізмом Upgrade з токеном h2c і відповіддю 101 Switching Protocols. А от популярні браузери взялися підтримувати HTTP/2 лише поверх TLS — зокрема Firefox і Chrome заявили це прямо. Тому в браузері працює формула «TLS з ALPN — де-факто вимога», причому з умовою й на боці сервера: він має вміти узгоджувати протокол через ALPN, інакше браузер підніме HTTP/1.1. Прямий наслідок для тестувальника: стенд, відкритий по http://, лишиться на HTTP/1.1 за будь-яких налаштувань сервера, і тікет про це заводити не треба.
Як клієнт і сервер узагалі домовляються про версію?
Спосіб залежить від версії. Для HTTP/2 їх три: узгодження через ALPN усередині рукостискання TLS, апгрейд відкритого зʼєднання без попереднього знання і старт відкритого HTTP/2 із попереднім знанням. Рекомендований — перший, бо протокол вибирається всередині вже потрібного рукостискання й додаткових не коштує. З HTTP/3 логіка інша: клієнт не може просто «спробувати QUIC», він спершу має дізнатися, що така точка існує. оголошує її заголовком відповіді Alt-Svc з токеном h3 (у HTTP/2 те саме може приїхати кадром ALTSVC), і лише отримавши цей запис, клієнт може підняти QUIC-зʼєднання, вибравши h3 уже як ALPN-токен. Коли UDP у мережі зарізаний, підняти QUIC не вийде — і тоді клієнтові радять повернутися до версій HTTP, що працюють поверх TCP: сайт відкриється, просто по HTTP/2.
У Network видно, що перший запит пішов по h2, хоча сервер підтримує HTTP/3. Це баг?
Ні, це нормальний порядок подій. Браузеру нізвідки знати про точку HTTP/3 до першої відповіді — саме в ній приїжджає Alt-Svc, і лише наступні запити він пробує по QUIC. Тому перше завантаження часто повністю проходить поверх TCP, і це не привід заводити тікет. Із того самого механізму випливає ще два спостереження. Версія — властивість конкретного запиту, а не сайту: в межах однієї сторінки цілком законно уживаються http/1.1, h2 і h3 — усе залежить від того, з ким і про що вдалося домовитися. І версію здатен «зняти» проміжний вузол: домовленість про зʼєднання існує лише між двома сусідами в ланцюгу й наскрізною не буває, тому браузер і origin цілком можуть бачити різні картини.
Що QUIC дає понад стек TCP + TLS?
Три речі, які варто називати списком. Перше — потоки з власним контролем потоку: мультиплексування переїхало в транспорт, тому HTTP поверх QUIC нічого не мультиплексує сам, а втрата в одному потоці не гальмує інші. Друге — низьколатентне встановлення зʼєднання: криптографічне й транспортне рукостискання злиті в одне, заразом там узгоджуються транспортні параметри. Третє — міграція між мережевими шляхами. До цього обовʼязково додають шифрування: QUIC першої версії використовує TLS 1.3 або новішу як протокол рукостискання, тож незашифрованого HTTP/3 не буває взагалі. Дві дрібниці, які добре показують розуміння: схема http:// привʼязана до вміння приймати TCP-зʼєднання, тому прямого доступу по HTTP/3 до такого ресурсу не існує; а віддавати HTTP/3 сервер може на будь-якому UDP-порту, тож «а чому не 443» дефектом не є.
Що таке 0-RTT і чому це не просто «швидше»?
Це режим повторного зʼєднання, у якому клієнт відправляє прикладні дані ще до того, як почув відповідь сервера, — звідси й економія одного RTT. Ціну специфікація називає прямо: захисту від replay-атак там немає, тобто перехоплений ранній пакет можна відтворити знову. Наслідок практичний і жорсткий: не ідемпотентні операції — оплату, створення замовлення, списання — у ранній фазі зʼєднання відправляти не можна. Для тест-плану це окремий рядок, і перевіряють у ньому не таймінги, а перелік операцій, які застосунок узагалі погоджується виконати в 0-RTT. Формулювання «0-RTT — це обмін гарантій на швидкість» на співбесіді звучить набагато сильніше, ніж «це прискорення повторних зʼєднань».
Що таке міграція зʼєднання і як її перевіряти?
QUIC упізнає зʼєднання не за парою «IP + порт», а за ідентифікатором зʼєднання (connection ID), тому воно переживає зміну мережевого шляху чи переприсвоєння адрес у NAT — там, де TCP-зʼєднання просто розірвалося б. Звідси законний тест-кейс: активна сесія має пережити перехід із Wi-Fi у мобільну мережу, і перевіряти це треба на живій сесії, а не на холодному старті. Обмеження знати обовʼязково: право почати міграцію має тільки клієнт, і не раніше, ніж рукостискання підтвердилося, а нову адресу партнера доводиться підтверджувати валідацією шляху. Тому перемикання мережі до підтвердження рукостискання міграцією не є взагалі — специфікація її там забороняє, і «сесія відвалилася» в такому сценарії не доводить нічого. Другий бік того самого сюжету — конфігурація: специфікація радить дозволяти щонайменше сто одночасних потоків-запитів, тож дефіцит паралельності на HTTP/3-стенді шукають у налаштуваннях, а не в протоколі.
Як перевірити те, чим HTTP/3 справді відрізняється від HTTP/2?
Перше, що чекають почути, — чого робити не треба: звичайний smoke на офісному Wi-Fi перевіркою HTTP/3 не є. Уся різниця між версіями зосереджена в двох умовах — втрати пакетів і зміна мережі, — а на ідеальному дротовому каналі втрачати нічого, тож обидві версії поводяться однаково. Осмислений план виглядає так: під емуляцією втрат порівняти, як поводиться сторінка на h2 і на h3 (на HTTP/2 завмирає все одразу, на HTTP/3 — лише постраждалий потік), і окремо перевірити виживання активної сесії при перемиканні мережі. Перед будь-яким із цих прогонів версію треба не припускати, а побачити: у панелі Network є колонка Protocol, яка показує h2 чи h3 порядково, і типово вона прихована — вмикають її правою кнопкою по шапці таблиці. Поруч корисні ще дві колонки: Connection ID, де для одного домену на HTTP/1.1 буде розсип значень, а на HTTP/2 — одне-єдине, і Remote address, якою найлегше довести, що піддомени ведуть в одне місце.
Три кейси про одне й те саме: версія протоколу мовчазно змінює правила, за якими ви читаєте симптом. Спершу розбір гальмування, у якому діагноз залежить від версії; далі чотири тікети, що закриваються як «не дефект»; наприкінці — що з теми взагалі автоматизується, а що лишається ручним.
Кейс 1. «Один запит гальмує всю сторінку»: діагноз залежить від версії
Скарга типова: сторінка на мить завмирає повністю — не вантажиться жоден блок, потім усе оживає разом. У тікеті це виглядає як «підвисає бекенд», але перш ніж іти в логи застосунку, потрібні дві речі: увімкнена колонка Protocol у панелі Network і розуміння, що на різних версіях ця сама картина має різні причини.
| Що бачите | Версія в колонці Protocol | Найімовірніша причина | Дешева перевірка |
|---|---|---|---|
Запити стоять партіями, у колонці Connection ID кілька значень на домен | http/1.1 | черга запитів у зʼєднанні: паралельність обмежена кількістю каналів | порахувати одночасні запити до домену — стеля близько шести підтверджує гіпотезу |
Один Connection ID на «хост+порт», але завмирають усі потоки одночасно | h2 | втрата пакета на рівні TCP спиняє всі активні обміни | повторити під емуляцією втрат: на дротовому каналі симптом майже не відтворюється |
| Завмирає рівно один запит, сусідні їдуть далі | h3 | проблема в конкретному потоці, транспорт тут ні до чого | шукати в самому ендпоінті, а не в мережі |
| Критичний ресурс приходить пізно, хоча запитаний рано | h2 | пріоритезація: важливе стоїть за хвостом другорядного | порівняти порядок завершення запитів із порядком їх старту |
| Величезні заголовки (кукі, токен) на кожному запиті, паралельність просіла після релізу авторизації | h2 | суцільний блок полів займає зʼєднання, поки не доїде цілком | порівняти розмір заголовків запиту до й після релізу |
Три висновки, які економлять час.
- Однакова картина, різні винні. «Все завмирає одночасно» на HTTP/1.1 — це черга запитів, на HTTP/2 — втрата пакета в TCP, а на HTTP/3 обидва пояснення просто не працюють. Тому версію дізнаються до того, як формулюють гіпотезу, а не після.
- Мережеві умови — частина відтворення. Різниця між HTTP/2 і HTTP/3 живе там, де є втрати пакетів або зміна мережі. У кабінеті з дротовим інтернетом обидві версії поводяться однаково, тож «не відтворюється» тут нічого не доводить.
- Не всі гальмування транспортні. Якщо на
h3завмер один запит, а сусідні пройшли — це найкорисніший з усіх сигналів: транспорт відпадає, і залишається сам .
Кейс 2. Чотири тікети, які закриваються як «не дефект»
Кожен із них хоч раз доїжджав до розробників. Спільна риса: симптом реальний, а очікування — хибне.
| Тікет | Що насправді | Як перевірити за хвилину |
|---|---|---|
| «HTTP/2 не вмикається на локальному стенді» | стенд відкрито по http://, а браузери піднімають HTTP/2 лише поверх TLS з ALPN | подивитися схему в адресному рядку; на https-стенді той самий білд дасть h2 |
«HTTP/3 зламаний: перший запит пішов по h2» | так і має бути: спершу приходить Alt-Svc з токеном h3, і лише наступні запити браузер пробує по QUIC | подивитися заголовок alt-svc у першій відповіді, потім колонку Protocol у наступних рядках |
«Частина запитів на сторінці — не h3, отже сайт не на HTTP/3» | версія — властивість запиту, а не сайту: h3, h2 і http/1.1 законно співіснують в одному сеансі | відсортувати список запитів за колонкою Protocol і звірити хости |
| «HTTP/3 віддається не з 443 порту» | сервер має право віддавати HTTP/3 на будь-якому UDP-порту, і саме він оголошується в Alt-Svc | зіставити порт із alt-svc з тим, що видно в Remote address |
Ще два випадки з тієї самої серії, які варто ловити на етапі планування, а не після заведення тікета.
- «Увімкнули HTTP/2, а швидше не стало (або стало гірше)». Це можливий результат, а не обовʼязково поломка: коли всі обміни зведені в одне зʼєднання, грубого паралелізму шести каналів більше немає, і за поганої пріоритезації сторінка збирається довше, ніж на HTTP/1.1. Спершу дивляться порядок завершення критичних ресурсів, і лише потім заводять продуктивності.
- «Мережа перемкнулася — сесія відвалилася, міграція QUIC не працює». Перевірте момент перемикання: ініціювати міграцію може тільки клієнт і тільки після підтвердження , тож обрив до цієї точки міграцією не є взагалі. Коректний сценарій — активна сесія, яка вже обмінюється даними, і перехід із Wi-Fi у мобільну мережу посеред неї.
Кейс 3. Що з теми автоматизується, а що ні
Спокуса написати expect(protocol).toBe('h3') велика, і саме її варто погасити першою: керування зʼєднанням діє між сусідніми вузлами, тож проміжний здатен «зняти» версію, і тест почне падати від зміни в інфраструктурі, якої ніхто не анонсував. Автоматизувати варто те, що є контрактом застосунку, а не властивістю каналу.
Найстабільніший у темі — факт оголошення точки HTTP/3. Це звичайний заголовок відповіді, і перевіряється він без браузера.
import { test, expect } from '@playwright/test';
test('походження оголошує точку HTTP/3', async ({ request }) => {
const res = await request.get('/');
const altSvc = res.headers()['alt-svc'] ?? '';
// без цього заголовка браузеру нізвідки дізнатися, що QUIC-точка існує
expect(altSvc, 'у відповіді немає Alt-Svc з токеном h3').toContain('h3=');
});
Другий кандидат — розмір блоку заголовків. Він прямо повʼязаний із паралельністю на HTTP/2, і його регресію легко проґавити: заголовок додає одна команда, а платять за нього всі запити.
test('блок заголовків запиту не роздувся після релізу авторизації', async ({ page }) => {
const sizes: Promise<number>[] = [];
page.on('request', (req) => {
// allHeaders(), а не headers(): другий не віддає cookie — саме те, що роздуває блок
sizes.push(
req.allHeaders().then((headers) =>
Object.entries(headers).reduce((sum, [k, v]) => sum + k.length + v.length + 4, 0),
),
);
});
await page.goto('/dashboard');
const worst = Math.max(...(await Promise.all(sizes)));
// поріг беруть із заміру до релізу, а не зі стелі — цифра тут проєктна
expect(worst, 'заголовки запиту виросли: на HTTP/2 це бʼє по паралельності').toBeLessThan(8192);
});
І дрібниця, що працює на будь-якій версії: замість фіксованої паузи чекають на конкретну відповідь. Скільки зʼєднань і потоків підняв браузер — на це очікування вже не впливає.
// прив'язуємось до події, а не до секунд: транспорт може змінитися, контракт — ні
await page.waitForResponse((r) => r.url().includes('/api/orders') && r.ok());
Що дивитися і чому:
- Асерт на версію протоколу — ламкий за конструкцією. Версія залежить від сусіднього вузла, а не від застосунку, тож у продуктових їй не місце. Якщо версію все ж треба контролювати, робіть це окремою перевіркою інфраструктури з чесною назвою, а не всередині бізнес-сценарію.
Alt-Svcперевіряють на факт і на токен, а не на порт. Номер UDP-порту — вибір сервера, і він може змінитися без жодного релізу застосунку; прибитий до:443асерт зафейлиться на рівному місці.- Ліміт на заголовки — це тест продуктивності, замаскований під тест контракту. Він ловить те, чого не побачить жоден функціональний сценарій: сторінка працює, просто кожен запит тягне на собі зайвий кілобайт. Тільки рахувати треба по
allHeaders():headers()не віддає cookie, тобто мовчки викине з підрахунку найтовщий заголовок. - Втрати пакетів і зміну мережі лишають ручному прогону. Ці два сценарії й становлять усю практичну різницю між HTTP/2 і HTTP/3, але вони вимагають керування мережевими умовами, а не браузером, — тож у чеклист релізу вони йдуть як ручні кроки з описаними умовами, а не як e2e-тест.
- Перелік операцій, дозволених у 0-, перевіряють головою, а не тестом. Питання не в таймінгах, а в тому, чи може оплата або створення замовлення поїхати в ранній фазі зʼєднання, де захисту від
replay- немає. Це рядок у тест-плані й предмет розмови з бекендом.
Що версія міняє, а що ні
- Можу пояснити, чому переїзд на HTTP/2 чи HTTP/3 не змушує переписувати (семантика — методи, , заголовки — спільна для всіх версій, версійне лише подання) і чому «тест зламався через HTTP/2» — гіпотеза, яку звужують до розміру заголовків, стелі паралельних потоків або поведінки проміжного вузла.
- Знаю три відмінності HTTP/2 від HTTP/1.1 у формулюванні MDN: бінарний формат, мультиплексування, стиснення полів заголовків.
Паралельність на HTTP/1.x
- Можу пояснити, чому одне зʼєднання HTTP/1.x дає одну чергу і чому єдиний вихід — кілька зʼєднань; при цьому «до шести на домен» подаю як практику браузерів, а не як норму RFC.
- Знаю різницю домен- тоді й тепер: на HTTP/1.1 множив паралельність, на HTTP/2 шкодить, а реалізації ще й обʼєднують зʼєднання назад (connection coalescing).
- Памʼятаю модальність рекомендації HTTP/2 про одне зʼєднання на «хост+порт»: це
SHOULD NOTз винятками (заміна зʼєднання, різні SNI, різні клієнтські сертифікати), а не заборона.
HOL-блокування
- Розводжу два рівні блокування: прикладний (черга запитів у зʼєднанні) і транспортний (втрата пакета в TCP) — і знаю, яка версія закриває який.
- Можу пояснити механіку транспортного рівня: потоки HTTP/2 не видні механізмам відновлення втрат TCP, тому один втрачений пакет спиняє всі активні обміни.
- Знаю, чому HTTP/3 цей рівень закриває (QUIC гарантує порядок лише всередині потоку, а кожна пара «запит-відповідь» займає окремий потік) і який залишок лишається — блокування через саме стиснення, тому QPACK дає кодувальнику вибір.
- Можу назвати умову, за якої HTTP/2 буває повільнішим за HTTP/1.1: погана пріоритезація там, де грубого паралелізму кількох TCP-зʼєднань уже немає.
HTTP/2 зсередини
- Розрізняю кадр (найменша одиниця обміну) і потік (незалежна двонаправлена послідовність кадрів) і можу описати мультиплексування як перемежовування їхніх кадрів в одному зʼєднанні.
- Знаю, що
SETTINGS_MAX_CONCURRENT_STREAMSкожна сторона оголошує для партнера, тож стелю клієнта задає сервер — і туди дивляться при впертому e2e чи навантаженні. - Можу пояснити, чому суцільний блок полів робить роздуті кукі й великі токени дорогими: поки блок їде кадрами
HEADERSіCONTINUATION, зʼєднання зайняте лише ним. - Знаю межі сервер-пушу: прогноз має враховувати кеш клієнта, клієнт вимикає режим через
SETTINGS_ENABLE_PUSH = 0, а в HTTP/3 сервер мовчить, доки не приїде кадрMAX_PUSH_ID.
Узгодження версії
- Знаю різницю «стандарт HTTP/2 TLS не вимагає» vs «браузери вимагають»: відкритий шлях існує через
Upgradeз токеномh2cі відповідь101 Switching Protocols, але стенд наhttp://лишиться на HTTP/1.1 за будь-якого конфігу, і це не дефект. - Можу описати виявлення HTTP/3 —
Alt-Svcз токеномh3у відповіді, потім ALPN-токен у QUIC-, а при заблокованому UDP на версії поверх TCP — і розумію наслідки: перше завантаження часто йде поh2, а в межах однієї сторінки нормально уживаютьсяhttp/1.1,h2іh3.
QUIC, HTTP/3 і діагностика
- Можу назвати три властивості QUIC понад TCP+TLS (потоки з власним контролем потоку, злите низьколатентне рукостискання, міграція між мережевими шляхами) і памʼятаю, що незашифрованого HTTP/3 не буває, а прямого доступу по HTTP/3 до
http://-ресурсу не існує взагалі. - Розумію ціну 0-: захисту від повторного відтворення там немає, тож перевіряють не таймінги, а перелік операцій, які застосунок дозволяє в ранній фазі зʼєднання.
- Можу описати міграцію зʼєднання через ідентифікатор зʼєднання і назвати її межі: ініціює лише клієнт, лише після підтвердження рукостискання, з валідацією нового шляху.
- Версію не вгадую, а вмикаю колонку
Protocol(типово прихована; поруч читаюConnection IDіRemote address) і памʼятаю, що проміжний вузол здатен «зняти» версію — керування зʼєднанням діє між сусідніми вузлами, а не наскрізно. - Фіксую версію протоколу в описі середовища (її оновлення не є релізом застосунку) і перевіряю різницю HTTP/2 з HTTP/3 емуляцією втрат та зміною мережі на активній сесії, а не smoke на офісному Wi-Fi.
Квіз
Перед стартом
- Питань: 17
- Поріг «зараховано»: ≥70% правильних відповідей.
- Результат впливає на прогрес; завалені питання підуть у чергу повторення.
- Квіз впливає на компліт теми: тема стає «пройдено», лише коли прочитано теорію І квіз складено на ≥70%.
Питання
Які документи після ревізії специфікацій 2022 року спільні для всіх версій HTTP, а які версійні?