Відкрийте вкладку Network у браузері, перезавантажте будь-яку сторінку вдруге — і серед рядків із кодом 200 обов’язково з’явиться кілька зі статусом 304. Клієнти часто питають, що це означає і чи не помилка це часом. Ні, не помилка. Це один із найкорисніших механізмів HTTP, про який більшість власників сайтів навіть не підозрює, поки не почне розбиратись, чому сторінка вантажиться повільно.
Що таке 304 Not Modified
Коли браузер вперше завантажує файл — картинку, стиль, скрипт — сервер віддає його повністю разом зі статусом 200 OK. Але браузер не викидає цей файл одразу після використання. Він зберігає копію в кеші й запам’ятовує кілька деталей: коли файл востаннє змінювався і своєрідний «відбиток» його вмісту.
При наступному відвідуванні браузер не питає сервер «дай мені файл ще раз». Він питає інакше: «у мене вже є цей файл, ось його відбиток — він досі актуальний?» Якщо сервер підтверджує, що файл не змінився, він відповідає кодом 304 Not Modified і не надсилає сам файл — жодного байта вмісту, тільки заголовки. Браузер бере копію з власного кешу і показує її.
ETag, Last-Modified і Cache-Control — три різні заголовки, які плутають
Тут і починається плутанина, бо три заголовки роблять схожі, але не однакові речі.
- Cache-Control каже браузеру, скільки часу взагалі не варто питати сервер: наприклад,
max-age=86400означає «цілу добу можеш просто брати з кешу, навіть не звертаючись до мене». Поки цей термін не минув, запиту з кодом 304 не буде взагалі — браузер віддасть файл з кешу миттєво, без жодного звернення до сервера. - Last-Modified — дата останньої зміни файлу. Браузер надсилає її назад серверу в заголовку If-Modified-Since, коли термін max-age вже сплив і треба перевірити актуальність.
- ETag — умовний хеш вмісту файлу, точніший за дату. Два файли можуть мати однакову дату модифікації на диску, але різний вміст (таке трапляється після деплою через CI/CD) — ETag це відловлює, Last-Modified часом ні.
Разом ці заголовки і формують ту саму перевірку «чи файл ще актуальний», результатом якої і стає 304.

Чому це реально прискорює сайт
Уявімо каталог інтернет-магазину. Головна сторінка тягне за собою стилі, кілька скриптів, іконки, логотип — разом легко набереться кілька мегабайт. Перший візит завжди найважчий: усе це треба завантажити з нуля. А ось другий, третій, десятий візит — зовсім інша історія, якщо кешування налаштоване правильно.
Клієнт повернувся на сайт через годину подивитись інший товар. Браузер уже має стилі й скрипти в кеші, і замість повторного завантаження двох мегабайт — кілька коротких запитів з відповіддю 304, кожен на кілька сотень байтів. На повільному мобільному інтернеті десь у дорозі різниця відчувається фізично: сторінка, яка мала б вантажитись п’ять секунд, відкривається майже миттєво.
Тут же криється і другий ефект, менш очевидний. Google враховує швидкість повторних завантажень при оцінці Core Web Vitals для мобільних користувачів, і сайт, що погано кешує статику, програє в цій метриці навіть якщо перший рендер швидкий.
Як перевірити, чи це взагалі працює
Найпростіше — відкрити DevTools (F12), перейти на вкладку Network, переконатись що галочка «Disable cache» знята (важливо саме зняти цю галочку, бо за замовчуванням у відкритих DevTools вона часто стоїть, і тоді кешування штучно вимкнене), і перезавантажити сторінку двічі.
Перше завантаження покаже переважно коди 200. Друге — якщо кешування налаштоване — має показати статус 304 навпроти стилів, скриптів, шрифтів, іконок. Колонка Size часто прямо підписує «(from disk cache)» або «(memory cache)» для файлів, які взагалі не пішли на сервер за перевіркою, і окремо 304 для тих, що пішли й отримали підтвердження.
Якщо після другого завантаження всі файли й далі показують 200 з повним розміром — кешування не працює, і варто дивитись, чому.
Що найчастіше ламає 304 у реальних проєктах
За нашим досвідом причин зазвичай кілька, і вони рідко пов’язані одна з одною.
Сервер узагалі не надсилає заголовки кешування. Буває на дешевому хостингу або коли Apache чи Nginx налаштований «за замовчуванням» без модуля expires чи явних правил для статики. Файли завжди йдуть з кодом 200, навіть якщо не змінювались роками.
CDN або плагін кешування конфліктують між собою. Один шар додає свої заголовки Cache-Control, інший їх перезаписує своїми — і на виході браузер отримує суперечливі інструкції. Ми бачили випадки, коли CDN примусово ставив короткий max-age поверх довшого серверного значення, і кешування фактично зводилось нанівець.
Занадто агресивний cache-busting. Річ корисна сама по собі — додавати до імені файлу версію (style.css?v=123), щоб браузер точно підхопив нову версію після оновлення. Але якщо версія генерується від часу збірки чи випадкового числа при кожному запиті сторінки, а не від реального вмісту файлу, браузер щоразу бачить «новий» файл і кешування ламається саме тими інструментами, які мали його прискорювати.
WordPress-плагіни оптимізації самі часом винні: якщо плагін мінімізації CSS чи JS генерує нове ім’я файлу при кожному кеші сторінки, ефект той самий — старий кеш браузера просто ніколи не використовується.
Чим це відрізняється від кеш-плагінів на кшталт WP Rocket чи W3 Total Cache
Тут часто виникає плутанина, бо обидва механізми звуться «кешування», але працюють на різних рівнях.
Плагін повного кешування сторінок зберігає готовий HTML на сервері й віддає його наступному відвідувачу без повторного звернення до бази даних і PHP — це прискорює саме генерацію сторінки. 304 працює зовсім в іншому місці: він каже браузеру не завантажувати повторно статичні файли, які й так уже є в нього на диску. Одне економить час сервера, друге — час і трафік на боці клієнта.
Найкращий результат — коли обидва механізми працюють одночасно. Плагін кешування прискорює віддачу самої HTML-сторінки, а правильні заголовки кешування прискорюють усе, що ця сторінка підвантажує. Без другого перше все одно лишає браузер щоразу тягнути кілька мегабайт стилів і скриптів заново.

Що з цим робити
Якщо перевірка в DevTools показала суцільні 200 замість очікуваних 304 — почніть з заголовків Cache-Control на сервері для статики (CSS, JS, зображення, шрифти), потім перевірте, чи CDN або плагін оптимізації їх не перезаписує тихцем. Це не та задача, яку варто вирішувати навмання — один неправильний заголовок може або взагалі вимкнути кешування, або, навпаки, змусити браузер показувати застарілу версію файлу після оновлення сайту, а це вже інша, неприємніша проблема.