vyvchy
    Теми розділу

    03 · Веб і мережі для AQA

    DevTools: вкладка Network і дебаг

    Зміст

    «Не працює» — найдорожче речення в баг-репорті: воно нічого не каже ні розробнику, ні тобі самому через тиждень. Вкладка Network в інструментах розробника (DevTools) — вікно між тим, що видно на екрані, і тим, що насправді літає між клієнтом і сервером. Кожен її рядок — один мережевий запит сторінки: HTML, картинки, скрипти, шрифти й фонові звернення до API. Вона перетворює «щось зламалося» на твердження, з яким можна працювати: «POST /api/orders повернув 422, у тілі — email already taken, Authorization присутній, кеш вимкнено».

    Ця глава — канонічний виклад теми на сайті: інші глави посилаються сюди по механіку панелі. Назви кнопок, колонок і прапорців далі — за довідником Chrome DevTools. Механіка Playwright і trace viewer — предмет розділу про інструменти; тут лише те, що видно у браузері.

    Наша практика (не канон). Оцінка «прилад діагностики номер один для AQA» і сам зразок формулювання з попереднього абзацу — наші: довідник DevTools таких тез не містить, він описує інтерфейс.

    Рядок запиту, колонки й фільтри

    Правило, яке нічого не коштує і рятує півгодини: панель відкривають до того, як відтворювати проблему. DevTools пишуть запити автоматично, але лише поки відкриті. Preserve log зберігає записи крізь переходи між сторінками.

    Наша практика (не канон). Найдорожчий випадок, на якому це видно, джерело не називає — його додаємо ми: без Preserve log редірект після логіну зітре саме те, що ви хотіли роздивитися, тож для сценаріїв із входом, перенаправленнями й багатокроковими формами прапорець вмикають наперед.

    Типовий набір колонок — Name, Status, Type, Initiator, Size, Time і Waterfall. Status показує або код HTTP, або окреме значення CORS error для запитів, що впали через ; Type — MIME-тип ресурсу; Size — заголовки плюс тіло, як їх віддав сервер; Time — повну тривалість до останнього байта; Waterfall — розкладку активності запиту в часі. Решту колонок вмикають правою кнопкою по шапці таблиці, і дві з них закривають половину «складних» питань: Protocol (h2 для HTTP/2, h3 для HTTP/3) і Connection ID — ідентифікатор з'єднання, у якому пішов запит. Через Response Headers і пункт Manage Header Columns додається власна колонка під конкретний заголовок відповіді.

    Фільтри дворівневі: кнопки типів ресурсу (All, Fetch/XHR, JS, CSS, Img, Doc, WS та інші) і текстове поле з властивостями — status-code:500, method:POST, domain:api.example.com. Дві деталі, на яких плутаються майже всі: інверсію дає окремий прапорець Invert, а не мінус на початку; кілька властивостей з'єднуються лише через AND.

    Обраний запит розкладається по вкладках Headers (блоки General, Response Headers, Request Headers), Payload, Response і Preview. Журнал експортується у HAR — JSON-запис сесії; типовий експорт санітизований, без Cookie, Set-Cookie й Authorization, тому його безпечно чіпляти до тікета. HAR можна завантажити й назад у DevTools і розбирати чужу сесію як власну.

    У Firefox це не ті самі колонки з іншими підписами — це інший спосіб показу. Різниця дорога саме в діагностиці збоїв: там, де Chrome пише текстом ((failed), CORS error, (blocked:origin)), Firefox лишає Status порожнім, якщо відповіді не було, або малює для заблокованих «red circle with a diagonal slash» — тобто підказка графічна, і той, хто шукає слово «failed», не знайде нічого. Причина блокування живе в іншій колонці, Transferred, і словами: «CSP», «Malware», «CORS Missing Allow Origin», «Blocked by [Name of Extension]» — останній навіть називає розширення поіменно, чого Chrome у своєму ERR_BLOCKED_BY_CLIENT не робить. Назви теж свої: Chrome Name — Firefox File, Type описаний прямо як «Content-type of the response», колонки Transferred у Chrome немає взагалі, а перемикач збереження журналу зветься «Enable persistent logs» у Settings, а не Preserve log на панелі. Плюс два сигнали без аналога в Chrome: іконка черепахи при перевищенні порогу очікування сервера (типово 500 мс, ключ about:configdevtools.netmonitor.audits.slow) і трикутник біля домену при слабких шифрах.

    Про Safari тут навмисно не сказано нічого: довідки Web Inspector у нашому реєстрі джерел немає, а переносити на неї спостереження про Firefox — це вигадувати, а не описувати.

    Життєвий цикл запиту як рамка читання логу

    Колонки відповідають на питання «що сталося», вкладка Timing — «де згорів час».

    DNS Lookup

    Initial connection
    TCP + TLS

    Request sent

    Waiting (TTFB)
    сервер думає

    Content Download
    тіло тече каналом

    DNS Lookup

    Initial connection
    TCP + TLS

    Request sent

    Waiting (TTFB)
    сервер думає

    Content Download
    тіло тече каналом

    Найважливіша фаза — Waiting (TTFB): у неї входить один плюс час на підготовку відповіді. Довга Waiting — це бекенд, а не «повільний інтернет». Тут же пастка з абревіатурою: під живуть два різні виміри. Навігаційний TTFB рахують від запиту сторінки до першого байта, і він включає DNS та встановлення з'єднання; фаза Waiting (TTFB) починається вже після того, як з'єднання встановлено.

    Стан pending означає, що запит ініційовано, а повної відповіді ще немає: або сервер думає, або запит стоїть у черзі через ліміт одночасних з'єднань до . Про події документа: DOMContentLoaded каже, що HTML розпарсено й DOM побудовано, load — що завантажено початкові ресурси з картинками й стилями, і жодна не засвідчує подальших запитів, які застосунок часто починає вже після load. Повний розбір — глава «Життєвий цикл запиту».

    Заголовки й тіло: що читати першим

    HTTP-повідомлення влаштоване однаково в запиті й відповіді: стартовий рядок, заголовки, порожній рядок як межа метаданих і необов'язкове тіло. Заголовки (headers) передаються перед вмістом; усе після порожнього рядка і є тіло (body). Мінімум, який читають першим: Content-Type описує медіа-тип тіла, Content-Length — скільки байтів читати, Accept — побажання клієнта щодо формату, Authorization — облікові дані. Помилковий Content-Type при ручному формуванні тіла — класична причина , і канонічний код тут 415, а не 400.

    Вкладка Payload показує тіло запиту — параметри рядка запиту й дані форми. Тіло в GET синтаксис не забороняє, але воно не має загальновизначеного значення й генерувати його клієнту не рекомендовано, тож параметри летять у самому URL (глава «URL і кодування»). Завантаження файлів видно як multipart/form-data: тіло розбите на частини з власними міні-заголовками, а розділяє їх рядок-роздільник, оголошений параметром boundary в Content-Type. У HTTP/2 повідомлення загорнуті в бінарні кадри, але логічна модель «метод або статус плюс заголовки плюс тіло» лишається — саме її показує панель. Канон — глава «HTTP: методи, структура, заголовки».

    Статус-коди й редиректи в ланцюжку

    Колонка Status — перше, куди дивляться. Перша цифра задає клас: 1xx інформаційні, 2xx успіх, 3xx перенаправлення, 4xx помилка клієнта, 5xx помилка сервера. поруч із кодом не можна: RFC називає її необов'язковою й велить клієнту ігнорувати, а HTTP/3 її взагалі не передає.

    Пари, які плутають найчастіше: 400 — «я не зрозумів, що ти написав», 422 — «я зрозумів, але так не можна»; 401 — «не автентифікований», 403 — «автентифікований, але прав немає»; 409 — конфлікт із поточним станом; 429 — перевищено , у відповіді може бути Retry-After. У класі 5xx розрізняють 502 (некоректна відповідь від апстріму), 503 (сервер тимчасово не готовий) і 504 ( не дочекався).

    Редирект (redirect) ініціює сервер: код на 3 і заголовок Location. Постійні 301 і 308 кажуть, що стару адресу більше не слід використовувати; при тимчасових 302, 303, 307 канонічною лишається початкова. Практична різниця: 301 і 302 гарантують незмінність методу лише для GET — інший метод клієнт може підмінити на GET і втратити тіло; 307 і 308 зберігають і метод, і тіло; 303 навмисно міняє метод на GET.

    Щоб ланцюг пережив перехід між сторінками, у панелі потрібен увімкнений Preserve log — і це ж пояснює, чому редирект легко проґавити: клієнти йдуть за перенаправленнями автоматично, і ви бачите фінальний 200, не помітивши зламану ланку (виняток — curl, який без -L за редиректом не піде). Окремо: 304 Not Modified формально теж 3xx, але це не перенаправлення — сервер підтверджує, що збережена копія валідна, і не передає тіло. Канон — глава «HTTP статус-коди».

    Звідки взялася стара відповідь: кеш і Service Worker

    «Виправили, задеплоїли, а на екрані старе» — класика з чотирма домівками: HTTP-кеш браузера, кеш Service Worker, CDN чи проміжний й кеш усередині самого застосунку.

    Прапорець Disable cache відтворює досвід відвідувача, який заходить уперше; область його дії — панель, а щоб кеш лишався вимкненим в інших панелях DevTools, є панель Network conditions. Далі читають заголовки: поки вік відповіді не перевищив термін свіжості, вона свіжа й мережею не йде взагалі; після цього кеш надсилає умовний запит із валідатором (ETag у If-None-Match, Last-Modified у If-Modified-Since), і 304 означає, що копію можна перевикористати без передачі тіла. Пастка з назвами директив: no-cache — не «не кешувати», а «не віддавати без валідації»; зберігання забороняє no-store.

    Service Worker — окремий і найупертіший рівень: подієвий , зареєстрований на конкретне походження і шлях, працює як проксі між застосунком, браузером і мережею й вирішує, віддати відповідь зі свого сховища Cache API чи піти в мережу. Cache API з HTTP-кешем не пов'язаний, тож правильні заголовки на бекенді на нього не впливають; доступний він лише в захищеному контексті — по HTTPS, з винятком http://localhost. «Примару після деплою» пояснюють дві деталі: за наявного активного воркера нова версія лишається в стані очікування, а під час активації події fetch ставляться в чергу. Канон — глава «Кешування».

    Скільки з'єднань і яка версія протоколу

    З'єднання HTTP/1.x серіалізує запити: наступний іде після відповіді на попередній. Щоб це обійти, браузери відкривають до кожного домену кілька паралельних з'єднань (parallel connections) — нинішнє поширене значення шість на домен. Шість — поточна практика браузерів, а не норма протоколу; у RFC такого числа немає. На HTTP/2 картина протилежна: специфікація каже клієнту не відкривати більш ніж одне з'єднання на пару «хост плюс порт», (pipelining) у сучасних браузерах вимкнений, а домен- MDN позначає як застарілий. Скільки з'єднань браузер підняв насправді, не вгадують — вмикають колонку Connection ID.

    Версію протоколу теж не «вмикають»: про неї домовляються на старті. Стандарт HTTP/2 не вимагає TLS, але браузери вимагають — Firefox і Chrome заявили, що піднімають його лише поверх TLS, а умова з боку сервера — вміння узгоджувати протокол через ALPN усередині . Практичний наслідок: локальне середовище на http:// завжди піде по HTTP/1.1, і це не дефект. Колонка Protocol показує картину порядково: h2, h3 і http/1.1 можуть співіснувати на одній сторінці. Ще одна межа: керування з'єднанням діє між двома сусідніми вузлами, а не наскрізно, тож проміжний проксі може «зняти» версію. Канон — глава «HTTP/2 і HTTP/3: еволюція протоколу».

    Затримка, пропускна здатність і тротлінг

    (latency) — час, за який дані долають шлях від джерела до призначення; міряють її зазвичай як RTT. (bandwidth) — скільки інформації проходить крізь з'єднання за одиницю часу. Вони незалежні: у TCP існує добуток «пропускна здатність × затримка», тобто канал буває водночас «товстим» і «довгим».

    У панелі це різні місця. Waiting — про сервер і один RTT; фаза завантаження вмісту визначається пропускною здатністю й розміром файла; колонка Time — повна тривалість до останнього байта. Перший запит до нового хоста дорожчий: у нього входять DNS, TCP-рукостискання й узгодження TLS. Звідси напрямок оптимізацій — менше RTT: з'єднань, мультиплексування HTTP/2, , CDN; HTTP/3 поверх QUIC ще й поєднує встановлення транспорту з узгодженням TLS.

    (throttling) — штучне обмеження швидкості: меню Throttling емулює швидкість завантаження, швидкість віддачі й мінімальну затримку. Поточні пресети — fast 4G, slow 4G і 3G, поруч режим Offline і прапорець Disable cache. Набір пресетів між версіями Chrome змінювався, тому для відтворюваних умов надійніше задавати власний профіль із фіксованими числами. Величини — глава «DNS, IP, порти та мережа».

    Наша практика (не канон). Роль тротлінгу для AQA джерела не описують — це наш кут. Для нас це не «перевірка продуктивності», а інструмент відтворення: він оголює стани завантаження (чи є спінер і скелетон, чи не «моргає» порожній екран) і витягує назовні гонки, яких на швидкому каналі не видно — класика тут кнопка, що лишається активною, поки запит іще летить, і дає подвійне надсилання. Звідси й формулювання, яке ми вживаємо як робоче: якщо тест падає на повільному профілі, він не «зафлакне колись на швидкому» — він просто ще не впав. І перед тим як списати падіння на «повільний CI», відтворюємо його локально на повільному профілі.

    AJAX і fetch: чому запиту немає в логу навігації

    AJAX — обмін даними із сервером у фоні, без повного перезавантаження сторінки. Технічно це старий XMLHttpRequest або сучасний Fetch API, і головний висновок для тестування такий: «сторінка відкрилась» ще не означає «дані на місці» — контент приїде окремим запитом після навігації, і в панелі він живе під фільтром Fetch/XHR, а не серед документів.

    Три речі видно саме тут і майже ніколи — у DOM. Перша: fetch() не реджектиться на 404 чи 500 успішно резолвиться об'єктом Response, тож статус перевіряють вручну, і response.ok істинний лише для діапазону 2xx. Друга: тіла запиту й відповіді — потоки, тож одне тіло не можна прочитати двічі. Третя: за замовчуванням fetch не шле облікових даних — режим credentials типово same-origin.

    У XMLHttpRequest корисно знати стани readyState: HEADERS_RECEIVED настає лише після того, як пройдено всі редиректи, у LOADING тіло ще тече, а DONE означає «операція завершилась» — успішно або з помилкою. Тобто readyState === 4 сам по собі про успіх не свідчить. Контекст — глава «Асинхронне завантаження: SPA/MPA, CSR/SSR».

    Кукі й сховища браузера у зв'язці з запитом

    Кукі (cookie) видає сервер заголовком Set-Cookie, а браузер повертає їх заголовком Cookie. Обмін асиметричний: сервер надсилає значення разом з атрибутами, а назад їдуть лише пари «ім'я = значення». Тому в Request Headers не видно ні Secure, ні HttpOnly, ні строку життя — атрибути дивляться в Set-Cookie у відповіді. HttpOnly означає, що кукі не видно скриптовим API (document.cookie), Secure — що вона не піде відкритим каналом. Фільтр панелі звужує пошук властивостями cookie-name, cookie-domain і response-header-set-cookie.

    Сховище браузера (Web Storage) поводиться протилежно: його вміст не їде на сервер ніколи автоматично. Якщо токен із localStorage має дістатися бекенду, застосунок мусить явно покласти його в заголовок або тіло — звідси проста вилка: немає Authorization у запиті, значить, шукайте баг у клієнтському коді. localStorage розділений лише за походженням, sessionStorage — ще й за вкладками, тож нова вкладка його не успадковує. Канон — глава «Кукі, сесії та сховище браузера».

    CORS і CSP: «запит пішов, а даних немає»

    Найпідступніший клас симптомів: рядок у панелі є, статус 200, тіло на місці — а в застосунку порожньо. Майже завжди це браузерна політика, а не бекенд.

    CORS перевіряє браузер. Postman, curl і HTTP-клієнт у бекенд-коді політики одного походження не реалізують і заголовки Access-Control-* ігнорують — тому «у Postman працює» контраргументом не є. Для запитів, складніших за ті, що дозволяє HTML-форма, спершу летить preflight — окремий запит методом OPTIONS із заявкою Access-Control-Request-Method і Access-Control-Request-Headers. У панелі це два рядки на один логічний запит: спершу дозвіл, потім самі дані — і Content-Type: application/json до безпечного переліку не належить, тому JSON-запит preflight викликає. Якщо OPTIONS дозволу не дав, справжній запит не піде взагалі. Друга типова картина — відповідь прийшла, а скрипт її не читає: за замовчуванням йому видно лише сім «безпечних» заголовків, решту сервер має перелічити в Access-Control-Expose-Headers. І окремо: заблокований CORS не означає, що дані не змінилися — простий запит сервер виконує повністю.

    CSP (Content Security Policy) працює на іншому рівні: сервер віддає заголовок Content-Security-Policy, і браузер за ним обмежує, звідки можна вантажити й виконувати вміст. Порушення видно не в Network, а в — тому «скрипт не виконався, а в мережі все зелено» так часто ставить у глухий кут. Content-Security-Policy-Report-Only дає ту саму політику в режимі спостереження. Автотестам сувора політика теж заважає: допоміжного скрипта чи inline-обробника буде заблокована. Канони — глави «CORS і політика одного походження» і «HTTPS, TLS і безпека».

    Перехоплення й підміна відповіді: що з цього видно у вкладці

    Механіка й таксономія дублерів — предмет глави «Перехоплення й мокання мережі»; тут лише те, що з цього видно в панелі.

    Обробник маршруту має три рішення: пропустити запит далі, підмінити відповідь або обірвати його. Перехоплення вибіркове — те, що не підійшло під шаблон, іде на реальний сервер, тож у панелі буде суміш справжніх і рукотворних відповідей. Обрив моделює недоступність сервісу, і код помилки береться із закритого переліку: 'connectionrefused', 'namenotresolved', 'internetdisconnected' — це різні класи збою, а не синоніми.

    // Підміняємо відповідь і перевіряємо, що UI показує саме стан помилки
    await page.route('**/api/orders', (route) =>
      route.fulfill({ status: 500, body: '{"error":"boom"}' })
    );

    Другий місток між панеллю й тестом — HAR: DevTools експортують сесію й уміють імпортувати її назад, а той самий запис може стати джерелом підмінених відповідей. Плата чесна: HAR-записи старіють, і тест лишається зеленим на даних, яких бекенд уже не віддає.

    WebSocket у вкладці

    Реалтайм шукають фільтром WS. З'єднання відкривається звичайним GET із заголовками Upgrade: websocket, Connection: Upgrade і Sec-WebSocket-Key, а успішний перехід підтверджує лише статус 101 Switching Protocols разом із Sec-WebSocket-Accept. Будь-який інший статус означає, що рукостискання не відбулося й далі діє звичайна семантика HTTP — тобто «сокет не працює» найчастіше видно як цілком звичайний код у першому ж рядку.

    Після рукостискання це самостійний протокол поверх TCP: усередині запису видно кожен кадр із напрямком, вмістом і часом. Схем дві — ws і wss; у проді вживають лише wss. Кореляції «запит — відповідь» тут немає, тому чекають на подію-наслідок, а не на фіксовану паузу. З'єднання живе в контексті виконання JavaScript вкладки, тож перезавантаження сторінки знищує його разом зі станом підписок. Канон — глава «WebSockets і реалтайм».

    Режим пристрою й Lighthouse: межі того, що вони міряють

    Режим пристрою (device mode) симулює мобільну , обмеження ЦП і мережі, а через панель Sensors — геолокацію й орієнтацію. Джерело називає межу прямо: це наближення першого порядку, а не запуск на пристрої, бо код виконується на вашому комп'ютері. Наслідків два. Обмеження ЦП відносне до потужності вашої машини, тому його числа не переносяться між комп'ютерами й не годяться в . Тип пристрою впливає не лише на вигляд: від нього залежить, які події породжує взаємодія — сенсорні чи кліки. Тому «на мобільному не працює свайп» перевіряють перемиканням типу, а шукають смугами медіазапитів.

    Lighthouse запускають трьома способами: у DevTools, із командного рядка або як Node-модуль. Оцінка доступності — зважене середнє перевірок доступності, кожна з яких дає pass або fail без часткового заліку, а ручні й низьковпливові перевірки в число не входять узагалі. Звідси головне: 100 балів не означає «доступно» — читають перелік проваленого, а не бал. будують на Node-варіанті або Lighthouse CI. Метрики клієнтської продуктивності — предмет розділу про продуктивність. Далі — глави «Кросбраузерність і адаптивна верстка» і «Семантичний HTML і доступність».

    Гонка станів: чому «то зелений, то червоний»

    Гонка станів (race condition) — залежність результату від порядку завершення асинхронних операцій там, де гарантій щодо цього порядку немає. У браузері кожне завдання обробляється повністю, перш ніж почнеться наступне, тому гонка виникає не всередині завдання, а між ними: два запити пішли, і хто відповість першим — питання мережі, а не коду.

    Панель Network — найкоротший шлях до діагнозу: ви бачите, який запит завершує дію, і чекаєте в тесті на нього. (hard wait) гонку не усуває, а маскує — воно не перевіряє стан, а сподівається, що за цей час усе встигне. Правильна альтернатива — очікування за умовою, де є стелею терпіння, а не запланованим простоєм. У коді застосунку ту саму гонку лікують скасуванням застарілого запиту через AbortController.

    // Чекаємо на конкретну відповідь, а не на «поки що-небудь станеться»
    await Promise.all([
      page.waitForResponse((r) => r.url().includes('/api/orders') && r.status() === 200),
      page.getByRole('button', { name: 'Створити' }).click(),
    ]);

    інструмента гасить частину гонок, але умови на кшталт «дані в таблиці оновилися» треба виражати явними очікуваннями стану. Далі — глави «Виконання JavaScript та event loop» і «Практичні сценарії AQA: флак і синхронізація».

    Алгоритм розбору «червоного» запиту

    Усе попереднє складається в одну послідовність, якою читають будь-яке «не працює». Ідуть згори вниз і зупиняються на першому збігу.

    Крок 0. Відтворити при відкритій панелі. Журнал пишеться, лише поки DevTools відкриті, тож панель відкривають до дії; за наявності переходів вмикають Preserve log, за підозри на кеш — Disable cache. Далі звужують список: кнопка Fetch/XHR для фонових викликів, потім властивість фільтра на кшталт status-code:500 чи method:POST.

    Крок 1. Прочитати Status. Клас коду ділить розслідування навпіл: 4xx — помилка клієнта, 5xx — помилка сервера. Далі за конкретним кодом: 401 — не автентифікований, дивимось Authorization і кукі сесії; 403 — автентифікований, але прав немає; 404 — не той URL; 400 і 422 — погані дані, і подробиці лежать у Payload та Response; 429 — уперлися в рейт-ліміт, і у відповіді може бути Retry-After. У класі 5xx фронтенд ні до чого: фіксують запит і йдуть до серверних логів, розрізняючи 502 (некоректна відповідь від апстріму), 503 (сервер тимчасово не готовий) і 504 (шлюз не дочекався).

    Крок 2. Коду немає взагалі. Значить, до логіки сервера не дійшло. Колонка Status має для цього окреме значення — CORS error; тоді читають Access-Control-* у відповіді й перевіряють, чи не зупинився логічний запит на preflight, бо без дозволу від OPTIONS справжній запит не піде. Якщо ж у мережі зелено, а вміст усе одно не зʼявився, дивляться консоль: порушення CSP видно саме там.

    Крок 3. 200, але «не працює». Найпідступніший випадок. Відкривають Response і Preview — сервер міг віддати 200 з тілом-помилкою або не тим форматом; перевіряють консоль — скрипт міг упасти вже на обробці відповіді; дивляться Size — якщо тіло взяте з кешу, ви читаєте старі дані, а не свіжу відповідь.

    4xx

    5xx

    CORS error або порожньо

    200, а результату немає

    Знайти запит: Fetch/XHR плюс фільтр

    Який Status?

    Клієнт: Headers, Payload, Response

    Сервер: зафіксувати запит, до логів бекенду

    До сервера не дійшло: preflight, консоль

    Response і Preview, консоль, Size

    4xx

    5xx

    CORS error або порожньо

    200, а результату немає

    Знайти запит: Fetch/XHR плюс фільтр

    Який Status?

    Клієнт: Headers, Payload, Response

    Сервер: зафіксувати запит, до логів бекенду

    До сервера не дійшло: preflight, консоль

    Response і Preview, консоль, Size

    Наша практика (не канон). Сам порядок кроків і поділ «застосунок / дані / політика браузера» — наша методика: довідник DevTools алгоритмів діагностики не пропонує, він описує інтерфейс. Сюди ж належить читання колонки Size на кроці 3: позначки (from memory cache) і (from disk cache), які означають, що мережею не передавалося нічого, у довіднику не описані — ми спираємося на власну практику. Дзеркальний випадок, який із цим плутають, джерельний: 304 Not Modified — це живий запит, у якому сервер підтвердив валідність збереженої копії й не передав тіло.

    Типові помилки

    • Виглядає як баг бекенду, а насправді — порожній журнал. DevTools пишуть запити, лише поки відкриті.
    • Виглядає як «редиректу не було», а насправді — його стерла навігація. Без Preserve log видно лише фінальний 200.
    • Виглядає як «у Postman працює, отже баг у фронті», а насправді — CORS. Політику застосовує браузер.
    • Виглядає як «сервер не відповів», а насправді — preflight. Один логічний запит дає два рядки, і якщо OPTIONS дозволу не дав, справжній запит не піде зовсім.
    • Виглядає як «скрипт не завантажився», а насправді — CSP. У Network зелено, бо порушення видно в консолі.
    • Виглядає як «HTTP/2 зламався», а насправді — локальний http://. У браузері HTTP/2 піднімається лише поверх TLS з ALPN.
    • Виглядає як «повільний бекенд», а насправді — розмір тіла. Довга Waiting — це сервер, довге завантаження — пропускна здатність і мегабайти.
    • Виглядає як «кеш винен», а насправді — Service Worker. Cache API з HTTP-кешем не пов'язаний.
    • Виглядає як , а насправді — незв'язане очікування. Тест, що падає на повільному профілі, уже некоректний.

    Підсумок

    • Рядок у Network — це факт, а не здогад. Статус, заголовки, тіло й таймінг перетворюють «не працює» на перевірюване твердження.
    • Половина відповідей ховається за вимкненими колонками й прапорцями: Protocol, Connection ID, Preserve log, Disable cache, Invert.
    • Фаза важливіша за загальний час. Waiting вказує на сервер, завантаження вмісту — на пропускну здатність і розмір, черга — на ліміт з'єднань.
    • Запит без даних у застосунку — майже завжди браузерна політика. CORS і preflight пояснюють це в Network, CSP — у консолі.
    • Тротлінг і Lighthouse нічого не «вимірюють остаточно». Перший — інструмент відтворення гонок, другий — зважений бал із ручними перевірками поза підрахунком.

    Можливі питання

    • «Покажи, як ти локалізуєш баг „кнопка не працює“». Дивляться на порядок дій: відкрити панель до відтворення, знайти запит, прочитати статус і тіло, відрізнити «запиту не було взагалі» від «запит пішов і повернув помилку».
    • «Що таке Waiting (TTFB) і чим воно відрізняється від TTFB у метриках?» Перевіряють, чи розумієте, що під однією абревіатурою живуть два виміри.
    • «У Postman запит проходить, у браузері — ні. Чому?» Питання про те, хто застосовує CORS; сильна відповідь називає preflight і те, що простий запит сервер усе одно виконує.
    • «Навіщо вмикати колонку Protocol Очікують h2, h3, http/1.1, розуміння ALPN і те, що локальний http:// по HTTP/2 не піде за побудовою.
    • «Скільки з'єднань браузер відкриває до одного домену?» Перевіряють акуратність формулювань: близько шести на HTTP/1.1 як практика браузерів, а не норма RFC, і одне з'єднання на HTTP/2.
    • «Тест іноді зелений, іноді червоний. Ваші дії?» Чекають шляху «відтворити на повільному профілі, знайти запит, що завершує дію, прив'язати очікування до нього», а не «підняти таймаут».
    • «Як передати мережевий контекст у баг-репорт?» Очікують HAR і знання, що типовий експорт санітизований — без Cookie, Set-Cookie й Authorization.

    Джерела

    Рядок запиту, колонки й фільтри

    • Chrome DevTools — Network features reference — запис журналу лише за відкритих DevTools, Preserve log, склад і керування колонками, Protocol і Connection ID, власна колонка під заголовок, типи ресурсів і властивості фільтра, прапорець Invert та відсутність OR, вкладки запиту й санітизований HAR.
    • Firefox DevTools — Network request list — назви колонок (File, Type, Transferred), порожній Status і графічна позначка блокування, причини блокування словами в Transferred, «Enable persistent logs» у Settings, іконка черепахи з порогом 500 мс і трикутник при слабких шифрах.

    Життєвий цикл запиту як рамка читання логу

    Заголовки й тіло: що читати першим

    Статус-коди й редиректи в ланцюжку

    • RFC 9110 — HTTP Semantics — класи кодів, необов'язковість пояснювальної фрази, межа 4xx і 5xx, збереження методу для 307, 304 як підтвердження валідної збереженої копії.
    • MDN — HTTP response status codes — значення 400, 422, 401, 403, 409, 429 з Retry-After, 500, 502, 503, 504.
    • RFC 9112 — HTTP/1.1 (message syntax) — вимога клієнту ігнорувати пояснювальну фразу статусу.
    • RFC 9114 — HTTP/3 — HTTP/3 не передає версію й пояснювальну фразу статус-рядка.
    • RFC 6585 — Additional HTTP Status Codes — код 429 як реакція на перевищення рейт-ліміту.
    • MDN — Redirections in HTTPLocation і клас 3xx, постійні проти тимчасових, поведінка методу й тіла для 301/302/303/307/308, ціна кроку й петля редиректів.
    • curl — manual page — автопрямування клієнтів і потреба -L у curl.
    • Chrome DevTools — Network features reference — колонка Status і збереження журналу крізь навігацію.

    Звідки взялася стара відповідь: кеш і Service Worker

    • RFC 9111 — HTTP Caching — свіжа й застаріла відповідь, умовний запит із валідатором, зміст 304, різниця no-cache і no-store.
    • MDN — HTTP caching — евристичне кешування без Cache-Control і читання директив у відповіді.
    • MDN Glossary — CDN — проміжний спільний кеш між користувачем і origin-сервером.
    • Chrome DevTools — Network features referenceDisable cache як емуляція першого візиту й панель Network conditions для інших панелей.
    • MDN — Service Worker API — воркер як проксі між застосунком і мережею, реєстрація на походження й шлях, захищений контекст, стан очікування нової версії.
    • web.dev — The Offline Cookbook — Cache API окремо від HTTP-кешу й черга подій fetch під час активації.

    Скільки з'єднань і яка версія протоколу

    • MDN — Connection management in HTTP/1.x — серіалізація запитів у HTTP/1.x, шість паралельних з'єднань на домен як поточна практика, вимкнений , застарілий домен-шардінг, hop-by-hop-природа керування з'єднанням.
    • RFC 9113 — HTTP/2 — вимога не відкривати більш ніж одне з'єднання на пару «хост плюс порт».
    • High Performance Browser Networking — HTTP/2 — способи узгодження версії, TLS з ALPN як рекомендований, позиція браузерів щодо HTTP/2 лише поверх TLS.
    • caniuse — HTTP/2 protocol (features-json) — підтримка HTTP/2 у браузерах лише поверх TLS і потреба ALPN на сервері.
    • Chrome DevTools — Network features reference — колонки Connection ID і Protocol зі значеннями h2 та h3 і їх увімкнення вручну.

    Затримка, пропускна здатність і тротлінг

    AJAX і fetch: чому запиту немає в логу навігації

    Кукі й сховища браузера у зв'язці з запитом

    • RFC 6265 — HTTP State Management MechanismSet-Cookie у відповіді й Cookie в запиті, повернення лише пар «ім'я — значення» без атрибутів, зміст Secure і HttpOnly.
    • MDN — Using HTTP cookies — практичне читання атрибутів кукі й межа доступу скриптів.
    • MDN — Set-Cookie — заголовок, у якому атрибути видно повністю.
    • MDN — Web Storage API — поділ localStorage за походженням і sessionStorage за вкладками, дані не надсилаються на сервер самі.
    • Chrome DevTools — Network features reference — властивості фільтра для кукі й санітизований HAR без Cookie, Set-Cookie та Authorization.

    CORS і CSP: «запит пішов, а даних немає»

    • MDN — Cross-Origin Resource Sharing (CORS) — preflight методом OPTIONS і його заголовки, Content-Type: application/json поза безпечним переліком, Access-Control-Expose-Headers, перевірка на боці браузера, два записи на один логічний запит і зупинка справжнього запиту, якщо OPTIONS не дав дозволу.
    • WHATWG Fetch Standard — умови безпечного запиту без preflight і сім заголовків відповіді, видимих скрипту за замовчуванням.
    • MDN — Same-origin policy — простий запит виконується сервером повністю, навіть коли браузер не віддає відповідь скрипту.
    • W3C — Content Security Policy Level 3 — доставка політики заголовком, режими примусу й звіту, Content-Security-Policy-Report-Only як спосіб випробувати політику.
    • MDN — Content Security Policy (CSP) — блокування inline-коду суворою політикою й повідомлення про порушення в консолі.

    Перехоплення й підміна відповіді: що з цього видно у вкладці

    WebSocket у вкладці

    Режим пристрою й Lighthouse: межі того, що вони міряють

    Гонка станів: чому «то зелений, то червоний»

    Алгоритм розбору «червоного» запиту

    • Chrome DevTools — Network features reference — запис журналу лише за відкритих DevTools, Preserve log, Disable cache, фільтр за типом ресурсу й властивостями, значення CORS error у колонці Status, вкладки Payload, Response і Preview, зміст колонки Size.
    • RFC 9110 — HTTP Semantics — межа між класами 4xx і 5xx, 304 як підтвердження валідної збереженої копії.
    • MDN — HTTP response status codes — значення 400, 401, 403, 404, 422, 429 з Retry-After, 502, 503 і 504.
    • MDN — Cross-Origin Resource Sharing (CORS) — preflight методом OPTIONS і зупинка справжнього запиту без дозволу.
    • MDN — Content Security Policy (CSP) — порушення політики видно в консолі, а не в мережевій панелі.

    Пояснення

    «Поясни» працює з власним API-ключем Anthropic: запит іде з вашого браузера прямо до Anthropic.

    Свій API-ключ (BYOK)

    Вставте власний ключ Anthropic — пояснення працюватиме на реальній моделі. Ключ зберігається лише у вашому браузері (localStorage), нікуди не надсилається, крім api.anthropic.com, і не логується.