Перейти до вмісту

Блог ·

Значок, що ставив куку на кожній сторінці

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

Автор: Provibr

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

Це був один тег зображення в підвалі. Значок каталогу запусків, завантажуваний просто з платформи, яка його видає, бо саме так такий значок і належить вбудовувати і бо число на ньому має бути живим.

Що може зробити тег зображення

Значок віддає хост API, що стоїть за Cloudflare, а Cloudflare відповідає на запити своєю кукою керування ботами: __cf_bm, SameSite=None, Secure, з областю на домені видавця значка. Це не є рішенням сайту, чий це значок. Це те, що робить CDN, на SVG, при кожному завантаженні сторінки, для кожного відвідувача.

На це відгукуються дві перевірки Lighthouse. Перевірка сторонніх кук важить пʼять із двадцяти восьми ваг у цій категорії, а зауваження інспектора важить одну. Шість ваг втрачено на зображенні. У тридцяти восьми вимірюваннях попереднього раунду це і був увесь розрив між 78 і 100.

Третій наслідок є тим, якого не ловить жодна оцінка. IP-адреса кожного відвідувача йшла до компанії, з якою він не обирав говорити, на кожній сторінці, в обмін на число в підвалі.

Вилучити його теж не є відповіддю

Ми вже записали цей компроміс у коментарі кількома місяцями раніше: якщо колись схочете мати це без банера згоди, шляхом є розміщення SVG у себе. З долученим контраргументом, а саме що розміщена в себе копія є фотографією. Значок існує, щоб показувати живий запис у каталозі; заморозьте байти, і ви маєте знімок запису.

Є третій шлях, і він стає очевидним лише тоді, коли ви розділите дві речі, які браузер робить водночас. Браузер забирає байти, і браузер встановлює зʼєднання. Проблемою є лише друге.

Тому значок тепер надходить із нашого власного походження, за шляхом у нашому власному API, і цей маршрут забирає джерело на сервері. Ті самі байти. Браузер відвідувача робить один запит, до нас. На дроті немає нічого, на що можна поставити куку, бо в сторінці відвідувача немає жодної третьої сторони взагалі. А число лишається живим, бо ми й далі питаємо.

Найкращі практики зросли з 78 до 100 у тридцяти двох із тридцяти шести вимірювань. Решта чотири є сторінками статей, які стоять на 96 через геть іншу кнопку третьої сторони, і це є окремим рішенням, а не залишком.

Що проксі винен тому, за кого він проксує

Віддавати чужі байти з власного походження означає змінювати те, чим вони є. SVG, завантажений через тег зображення, не може виконати скрипт; це є гарантією специфікації, і гарантією доброю. Але щойно ці байти йдуть із нашого домену, те, що в них, є нашим.

Тому маршрут перевіряє відповідь, перш ніж передати її далі. Ця перевірка навмисно не є очищувачем. Очищувач намагається зробити небезпечний вміст безпечним; ця ж відхиляє все, що не схоже на значок, який ми вже знаємо, і маршрут падає назад на заморожену копію. Найгіршим випадком є значок від цього ранку замість значка від цієї хвилини, і це ціна, яку варто платити за те, щоб ніколи не міркувати, що може містити чужа відповідь.

Дві з відмов стосуються саме того, заради чого вся ця зміна й була. SVG може посилатися на зовнішнє зображення, і він може посилатися на зовнішній ресурс з оголошення стилю. Будь-яке з двох сягнуло б третьої сторони на шар глибше за тег, який ми щойно прибрали, зсередини файлу, який ми віддаємо як власний. Перевірка, що дивилася б лише на скрипти, пропустила б обидва.

Падати до знімка, і то навмисно

Кожен шлях невдачі повертає заморожену копію зі станом 200. Мережева помилка, вичерпаний час, стан, що не є 200, тіло, якому перевірка не довіряє: усі вони дають 200, і значок усередині.

Міркування стосується того, як невдача виглядає. 404 або 502 на зображенні в підвалі кожної сторінки є піктограмою зламаного зображення на кожній сторінці, що читається як зламаний сайт, і то заради оздобного елемента. Трохи застарілий значок не читається ніяк.

Розплатою є те, що шлях невдачі несе короткий заголовок кешу, тоді як шлях успіху несе довгий. Інакше пʼятихвилинний збій у джерелі приколов би заморожену копію перед усіма на ціле вікно кешу.

Заморожена копія одна, і вона навмисно не живе як файл у прилюдному каталозі. Як файл вона мала б другу прилюдну адресу поруч із маршрутом, і майбутній раунд міг би цілком розумно вкинути тег зображення, що вказує просто на неї, а це тихо прибирає живу поведінку, заради збереження якої весь цей лад і існує. Тримана як стала, вона віддається лише через маршрут, який спершу пробує мережу.

Два кеші, що роблять різну роботу

Тут є два шари кешування, і плутанина між ними дає систему, яка або гатить у джерело, або показує застарілі байти назавжди.

Кеш даних середовища тримає відповідь джерела: із шестигодинною переперевіркою один відвідувач кожні шість годин спричиняє один вихідний запит, незалежно від навантаження. Заголовок кешу HTTP тримає нашу відповідь, на CDN і в браузері. Джерело ставить на власну відповідь чотири години; шість на нашому боці є навмисним півкроком ушир, аби збій там не скидав нас на заморожену копію в чотиригодинному ритмі.

Одна дрібна пастка, яка коштувала збірки. Next читає налаштування сегмента маршруту статично з джерела, тож експорт переперевірки мусить бути буквальним числом. Записати його виразом, навіть сталою, оголошеною кількома рядками нижче в тому самому файлі, означає обірвати збірку помилкою про хибне налаштування сегмента. Стала тепер читає з експорту, а не навпаки, тож число й далі рівно одне.

307, що був прапорцем запуску

Той самий раунд витратив час на щось, що виглядало як помилка маршрутизації і нею не було, і це варто записати, бо воно змарнувало попередній раунд цілком.

Коли виробничу збірку запускали локально, кожен голий маркетинговий шлях відповідав 307, перенаправляючи на самого себе. Не локалізовані шляхи, не маршрути API: саме голі. Це тижнями блокувало англійську половину кожного локального прочісування верстки і було записане як незʼясований дефект.

Річ у привʼязці хоста. Запущений із буквальною петльовою адресою як іменем хоста, Next лишає це значення таким, як воно є, тоді як порожнє або підстановочне імʼя хоста нормалізується до localhost. Початкова URL і походження, яке обчислює проміжний шар, тоді розходяться, переписування лишається абсолютним, маршрутизатор вважає його зовнішнім і заходить наново. Запущений із підстановочним значенням, яке вживає виробництво, або з localhost, усе відповідає 200.

Лагодити не було чого. Що треба було зробити, так це вписати у скрипт правильний рядок запуску і записати чому, бо дефект, який насправді є прапорцем, інакше буде наново відкритий наступною людиною з тією самою певністю.

Невдача, яку ми вирішили не лагодити

Третя річ із того самого раунду є навмисним нелагодженням, а такі речі заслуговують на запис принаймні так само ретельний, як полагодки.

Ми бачили 404 на шматках у полі: HTML, що посилається на файли JavaScript, яких уже немає. Поясненням виявився один заголовок. Головна сторінка несе вікно stale-while-revalidate завдовжки в рік, тож периферійний вузол CDN має право віддавати HTML зі старішої збірки дуже довго, а назви шматків у тому HTML належать тій збірці.

Ручка стоїть просто тут, і ми її не чіпали, бо саме та застаріла копія тримала сайт у відповідях під час циклу падінь бази даних двома тижнями раніше. Скоротити вікно означає виміняти рідке зламане завантаження на ще рідший цілковитий збій. Це є справжнім обміном, він належить тому, хто несе ризик, а робота раунду полягала в тому, щоб пояснити механізм, а не ухвалити рішення.

Що ми б записали

  1. Однакова оцінка на кожній сторінці вказує на щось, що спільне для кожної сторінки. Це найдешевша зачіпка, яку ви дістанете.
  2. Тег зображення є зʼєднанням, а не просто байтами. Усе, що CDN хоче зробити на запиті, він робить і на цьому.
  3. Розміщення в себе не є єдиною альтернативою вбудовуванню. Забирання на сервері зберігає живу поведінку і прибирає третю сторону зі сторінки відвідувача.
  4. Щойно ви віддаєте чужі байти, вони стають вашими. Перевіряйте їх, і перевіряйте саме на ті посилання, що знову відкрили б дірку, яку ви щойно закрили.
  5. Волійте застарілий знімок зламаному зображенню. Для оздоби видима невдача коштує більше за невидиму застарілість, доки вікно застарілості на шляху невдачі коротке.
  6. Не давайте замороженій копії прилюдної адреси. Усе досяжне колись буде звʼязане, і живий шлях тихо обійдуть.
  7. Знайте, який кеш що тримає. Один тримає відповідь джерела, другий тримає вашу, і їхні вікна відповідають на різні питання.
  8. Дещо червоне є прапорцем, а не хибою. Відтворіть механізм, перш ніж лагодити симптом, а якщо він виявиться вашою власною командою запуску, скажіть про це у скрипті.

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

Із платформної роботи над Provibr. Інше вимірювання, що стало зеленим із хибної причини, описано в виняток доступності, який себе вимірює, а поле, що тримало намір там, де належав факт, описано в майбутня дата не є розкладом виходу.

Читати далі

Почніть з одного хоста й одного агента

Створіть обліковий запис, встановіть агента однією командою та підключіть свій перший хост Proxmox. Пробний період триває 14 днів і не потребує платіжних даних.