HTTP-кэширование

Дата обновления перевода 2025-02-14

HTTP-кэширование

Природа насыщенных веб-приложений подразумевает, что они динамические. Вне зависимости от того, насколько эффективно ваше приложение, каждый запрос будет содержать больше работы, чем обслуживание статического файла. Обычно это нормально, но когда вам нужно, чтобы ваши запросы были молниеносно быстрыми, вам понадобится HTTP-кэшироваие.

Кэширование на плечах титанов

C HTTP-кэшированием, вы можете кэшировать страницы целиком (т.е. ответ), и затем, в обход приложения, отдавать кэшированные данные для каждого запроса. Конечно же, это не всегда возможно применить для очень динамичных сайтов, или всё же возможно? С помощью Включений крайней стороны (ESI) вы можете использовать силу HTTP-кэширования только для фрагментов вашего сайта.

Система кэширования Symfony отличается от других, так как она полагается на простоту и мощь HTTP-кэширования, как это определено в спецификации RFC 7234 - Кэширование. Вместо того, чтобы изобретать кэширование заново, Symfony пользуется стандартом, который определяет базовые коммуникации в Web. Как только вы поймёте основополагающие модели HTTP валидации и истечения срока кэша, вы будете готовы к управлению системой кэширования Symfony.

Так как HTTP-кэширование используется не только Symfony, существует множество статей по данной теме. Если вы новичок в HTTP-кэшировании, настоятельно рекомендуем вам прочитать статью Райана Томайко Вещи, которые делают кэши . Другим исчерпывающим источником является Учебное пособие по кэшу от Марка Ноттингема.

Кэирование при помощи кэширующего шлюза

При HTTP-кэшировании, кэш полностью отделён от вашего приложения и располагается между вашим приложением и клиентом, выполняющим запрос.

Работа кэша заключается в приёме запросов от клиента, и их передаче вашему приложению. Кэш также будет получать ответ от вашего приложения и перенаправлять его клиенту. Кэш является «посредником» в клиент-серверных коммуникациях между клиентом и вашим приложением.

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

Этот тип кeширования известен под именем "кeширующего HTTP шлюза". Существует много кeшеров такого типа, например: Varnish, Squid в режиме обратного прокси, а также обратный прокси Symfony.

Tip

Кэширующие шлюзы иногда называются кэшами обратного прокси, суррогатными кэшами или даже HTTP-акселераторами.

Обратный прокси Symfony

Symfony содержит обратный прокси (также называемый кэширующим шлюзом), написанный на PHP. Это не кэш обратного прокси с неполным функционалом вроде Varnish , однако это отличный способ начать.

Tip

Чтобы узнать детали о настройке Varnish, см. Как использовать Varnish для ускорения моего сайта.

Используйте опцию framework.http_cache, чтобы включить прокси для окружения производства :

1
2
3
4
# config/packages/framework.yaml
when@prod:
    framework:
        http_cache: true

Ядро незамедлительно будет вести себя как обратный прокси: кэшировать ответы из вашего приложения и возвращать их клиенту.

Прокси имеет разумную конфигурацию по умолчанию, но может быть тонко настроен через набор опций .

Когда в режиме отладки , Symfony автоматически добавляет заголовок X-Symfony-Cache к ответу. Вы можете также использовать опцию конфигурации trace_level и установить её как none, short или full, чтобы добавить эту информацию.

short добавит информацию только для основного запроса. Он написан кратким образом, что делает запись информации в ваших файлах логов сервера лёгкой. Например, в Apache вы можете использовать %{X-Symfony-Cache}o в заявлениях формата LogFormat. Эта информация может быть использована для извлечения общей информации о действенности кэша ваших маршрутов.

Tip

Вы можете изменить имя заголовка, используемо для информации об остлеживании, используя опцию конфигурации trace_header.

Обратный прокси Symfony - это отличный инструмент для использования при разработке вашего веб-сайта, или когда вы развёртываете веб-сайт на общем хосте, где вы не можете установить ничего, кроме PHP-кода. Но, написанный на PHP, он не может быть таким же быстрым, как прокси, написанный на C.

К счастью, так как все обратные прокси по сути одинаковы, вы должны иметь возможность переключиться на что-то более прочное - вроде Varnish - без каких-либо проблем. См. Как использовать Varnish

Делаем ваши ответы HTTP-кэшируемыми

Как только вы добавить кэш обратного прокси (например, как обратный прокси Symfony или Varnish), вы готовы кэшировать ваши ответы. Чтобы сделать это, вам нужно сообщить вашему кэшу, какие ответы являются кэшируемыми и на какое время. Это делается путем установки заголовков кэша в ответе.

HTTP определяет четыре заголовка ответакэша, которые вы можете активировать:

  • Cache-Control
  • Expires
  • ETag
  • Last-Modified

Эти четыре заголовка используются для того, чтобы помочь вам кэшировать ваши ответы с помощью двух разных моделей:

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

Все HTTP-заголовки, о которых вы будете читать, изобретены не Symfony! Они являются частью спецификации HTTP? которая используется сайтами по всей сети. Чтобы погрузиться в HTTP-кэширование, посмотрите документы RFC 7234 - Кэширование и RFC 7232 - Условные запросы.

Вам, как веб разработчику, настоятельно рекомендуется прочитать эту спецификацию. Её простота и сила, даже спустя более, чем десять лет после её написания, бесценны. Не бойтесь внешнего вида спецификации - её содержание много лучше, чем её обложка!

Кэширование окончания срока действия

Самый простой способ кэшировать ответ - это кэшировать его на определенное количество времени:

1
2
3
4
5
6
7
8
9
// src/Controller/BlogController.php
use Symfony\Component\HttpKernel\Attribute\Cache;
// ...

#[Cache(public: true, maxage: 3600, mustRevalidate: true)]
public function index(): Response
{
    return $this->render('blog/index.html.twig', []);
}

Благодаря этому новому коду, ваш HTTP-ответ будет иметь следующий заголовок:

1
Cache-Control: public, s-maxage=3600, must-revalidate

Он сообщает вашему обратному прокси HTTP кэшировать этот ответ на 3600 секунд. Если кто-либо запросит этот URL опять раньше, чем через 3600 секунд, ваше приложение вообще не не будеть задействовано. Если вы используете обратный прокси Symfony, посмотрите на заголовок X-Symfony-Cache, для отладки информации о попаданиях и промахах кэша.

Tip

URI запроса используется в качестве ключа кэша (разве что вы варьируете).

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

Tip

На самом деле, вы можете вручную инвалидировать ваш кэш, но это не ялвяется частью спецификации HTTP-кэширования. См. Девалидация HTTP-кэша .

Если вам нужно установить заголовки кэша для многих разных действий контроллера, посмотрите FOSHttpCacheBundle. Он предоставляет способ определять заголовки кэша, основываясь на образец URL и другие свойства запроса.

В конце-концов, для более детальной информации об окончании срока действия кэша, см. Срок действия HTTP-кэша.

Кэширование валидации

С кэшированием с окончанием срока действия, вам просто нужно сказать "кэшировать на 3600 секунд!". Но, когда кто-то обновляет кэшированный контент, вы не сможете увидеть его до тех пор, пока не истечет срок действия кэша.

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

Чтобы узнать больше, см. Валидация HTTP-кеша.

Безопасные методы: Кэширование только запросов GET или HEAD

HTTP кэширование работает лишь для "безопасных" HTTP методов (таких как GET и HEAD). Это означает 2 вещи:

  • Не пытайтесь кэшировать запросы PUT или DELETE. Это не сработает, и по хорошей причине. Эти методы не должны быть использованы при изменении состояния вашего приложения (например, удалении поста блога). Их кэширование будет предотвращать некоторые запросы от попадания и изменения вашего приложения.
  • Запросы POST обычно считаются некэшируемыми, но их можно кэшировать, когда они содержат ясную информацию о свежести. Однако, кэширование POST не широко реализуется, поэтому вам стоит его избегать, если это возможно.
  • Вам никогда не стоит изменять состояние вашего приложение (например, обновлять пост блога), во время ответа на запрос GET или HEAD. Если эти запросы будут кэшированы, будущие запросы могут никогда не попасть на ваш сервер.

Другие методы ответа

Класс Response содержит также множество других методов, относящихся к кэшу. Вот самые полезные из них:

1
2
3
4
5
// помечает ответ как "просроченный"
$response->expire();

// форсирует возврат ответа 304 без контента
$response->setNotModified();

В дополнение к этому, все основные HTTP заголовки, относящиеся к кэшу, могут быть установлены при помощи одного метода setCache():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// используйте этот метод, чтобы установить несколько настроек кэша за один вызов
// (этот пример перечисляет все доступные настройки кэша)
$response->setCache([
    'must_revalidate'  => false,
    'no_cache'         => false,
    'no_store'         => false,
    'no_transform'     => false,
    'public'           => true,
    'private'          => false,
    'proxy_revalidate' => false,
    'max_age'          => 600,
    's_maxage'         => 600,
    'immutable'        => true,
    'last_modified'    => new \DateTime(),
    'etag'             => 'abcdef'
]);

Tip

Все эти опции также доступны при использовании атрибута #[Cache()].

Инвалидация кэша

Инвалидация кэша не является частью HTTP-спецификации. Однако, она может быть очень ползеной для удаления различных записей HTTP-кэша, как только какой-либо контект вашего сайта обновляется.

Чтобы узнать больше, см. Аннуляция кэша.

Использование Включений крайней стороны

Когда на странице присутствуют динамические части, вам не удастся кэшировать целые страницы, а придется это делать по частям. Читайте Работа с включениями крайней стороны, чтобы узнать, как сконфигурировать разные стратегии кэширования для определенных частей вашей страницы.

HTTP-кэширование и сессии пользователей

Каждый раз, когда сессия начинается во время запроса, Symfony превращает ответ в приватный некэшируемый ответ. Это лучшее поведение по умолчанию, чтобы не кэшировать приватную инфомацию пользователя (например, корзину покупок, детали профиля пользователя и т.д.) и не отобазить её другим посетителям.

Однако, даже запросы, которые пользуются преимуществами сессии, могут быть кэшированы при некоторых обстоятельствах. Например, инфомация, связанная с какой-то группой пользователей, может быть кэширована для всех пользователей, принадлежащих к этой гуппе. Обработка этих продвинутых сценариев кэширования находится за пределами области действия Symfony, но их можно ррешить с помощью FOSHttpCacheBundle.

Для того, чтобы отключить поведение Symfony по умолчанию, которое делает запросы, использующие сессии, некэшируремыми, додайте следующий внутренний заголовок к вашему ответу и Symfony его не изменит:

1
2
3
use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;

$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');

Заключение

Symfony создан таким образом, чтобы следовать проверенным «правилам движения» в HTTP. Кэширование - не исключение. Овладение системой кэширования Symfony, подразумевает близкое знакомство с моделями кэширования HTTP и их эффективное использование. Это означает, что вместо того, чтобы полагаться только на документацию Symfony и примеры кода, вы получаете доступ к целому миру знаний, относящихся к кэшированию в HTTP и кэширующим шлюзам, таким как Varnish.