HTTP-заголовки кэширования (Cache-Control) 🚀 — подробный обзор
Опубликовано

HTTP-заголовки кэширования (Cache-Control) 🚀 — подробный обзор

 

Представьте, что вы каждое утро приходите в одно и то же кафе и спрашиваете бариста: «Какой кофе вы варите?». Он перечисляет все меню. На следующее утро вы снова спрашиваете то же, и он снова перечисляет. Это пустая трата времени, правда? Логичнее было бы запомнить тот небольшой перечень доступного кофе и спрашивать его только тогда, когда он изменится.

Именно так работает кэширование в браузере. Без него ваш браузер при каждом посещении страницы вынужден заново загружать каждую картинку, скрипт и стиль. Это медленно и дорого. HTTP-заголовки кэширования — это инструкции, которые сервер дает браузеру: «Запомни этот файл на неделю» или «Проверяй этот файл при каждом визите».

В этой статье я расскажу о том, как правильно настроить эти инструкции, чтобы ваш сайт летал, а сервер не «задыхался» от лишних запросов.

 

Главный игрок: Cache-Control

Раньше для кэширования использовали заголовок Expires, но сегодня стандартом де-факто является Cache-Control. Это мощный инструмент, который позволяет очень гибко управлять поведением кэша.

Он состоит из директив. Давайте разберем самые важные из них:

Директива Что она означает
max-age=3600 Файл считается «свежим» в течение указанного количества секунд (здесь — 1 час). Браузер даже не будет спрашивать сервер об этом файле, пока время не истечет.
public Файл может кэшироваться кем угодно: браузером, CDN, прокси-сервером. Идеально для статики.
private Файл предназначен для одного пользователя (например, страница профиля). Кэшировать может только браузер, но не CDN.
no-cache Внимание, ловушка! Это не значит «не кэшировать». Это значит «кэшируй, но перед каждым использованием спрашивай сервер, не изменился ли файл» (валидация).
no-store Вот это действительно «не кэшировать нигде и никогда». Используется для банковских данных и конфиденциальной информации.
must-revalidate Когда срок max-age истечет, браузер обязан проверить актуальность файла на сервере, а не использовать старую копию.

 

Как браузер узнает, что файл изменился? (Валидаторы)

Когда вы используете no-cache или когда истекает время max-age, браузер делает запрос к серверу: «У меня есть картинка, вот ее метка. Она все еще актуальна?». Для этого существуют два заголовка-валидатора:

  • ETag (Entity Tag): Уникальный хеш-код файла (например, "33a64df551425fcc55e4d42a148795d9f25f89d4"). Если хеш на сервере совпадает с тем, что есть у браузера, сервер отвечает 304 Not Modified (тело файла не передается).
  • Last-Modified: Дата последнего изменения файла. Менее точный, чем ETag, но тоже популярный.

 

Практика: как настроить кэширование

Настройка зависит от того, какой веб-сервер вы используете. Если вы не уверены, советую прочитать мою статью о разнице между Nginx и Apache.

 

Вариант 1: Nginx (Самый эффективный)

Добавьте этот код в блок server вашего конфигурационного файла:

# Кэширование статики (картинки, шрифты) на 1 год
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
    expires 365d;
    add_header Cache-Control "public, no-transform";
}
# Кэширование HTML (не кэшируем или кэшируем с проверкой)
location ~* \.(html)$ {
    add_header Cache-Control "no-cache";
}

 

Вариант 2: Apache (.htaccess)

Если вы используете Apache, добавьте этот код в файл .htaccess в корне сайта. Вам понадобится модуль mod_expires.

<IfModule mod_expires.c>
    ExpiresActive On    
    # картинки
    ExpiresByType image/jpg "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"    
    # CSS и JS
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"    
    # По умолчанию
    ExpiresDefault "access plus 2 days"
</IfModule>
# Дополнительный контроль заголовков
<IfModule mod_headers.c>
    <FilesMatch "\.(js|css|xml|gz|html)$">
        Header append Vary: Accept-Encoding
    </FilesMatch>
</IfModule>

 

Вариант 3: PHP (для динамического контента)

Иногда нужно запретить кэширование конкретной динамической страницы (например, корзины). Это можно сделать прямо в коде:

<?php
// Запрещаем кэширование
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
?>

 

Распространенные ошибки ⚠️

  1. Кэширование часто меняющихся файлов без версионирования. Если вы поставите max-age=1 год на style.css и измените дизайн, пользователи будут видеть старый дизайн еще год. Решение: меняйте имя файла при обновлении (например, style.v2.css или style.css?v=2).
  2. Использование public для приватных данных. Никогда не используйте public для страниц, где есть личные данные пользователя, иначе они могут остаться в кэше публичного прокси.
  3. Отсутствие заголовков. Если вы не пошлете никаких заголовков, браузер сам попытается «угадать», как кэшировать контент (Heuristic Caching), и результат может быть непредсказуемым.

 

Вывод: баланс между скоростью и актуальностью

По моему мнению, настройка заголовков кэширования — это искусство найти баланс. Вы хотите, чтобы пользователь загружал как можно меньше данных (долгий кэш), но при этом всегда видел актуальную версию сайта.

Мой рецепт прост: «агрессивно» кэшируйте статику (картинки, шрифты) с долгим сроком жизни, используйте версионирование файлов для CSS/JS, и будьте осторожны с кэшированием HTML-страниц, используя no-cache для динамического контента.

 

 

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *