Получение ресурсов по сети является медленным и дорогостоящим процессом:
- Большие ответы требуют большого количества обращений между браузером и сервером.
- Ваша страница не загрузится, пока все ее критически важные ресурсы не будут загружены полностью.
- Если человек заходит на ваш сайт с ограниченным тарифным планом на передачу мобильных данных, каждый ненужный сетевой запрос — это пустая трата его денег.
Как избежать ненужных сетевых запросов? HTTP-кэш браузера — ваша первая линия защиты. Это не обязательно самый мощный и гибкий подход, и вы имеете ограниченный контроль над временем жизни кэшированных ответов, но он эффективен, поддерживается во всех браузерах и не требует особых усилий.
В этом руководстве показаны основы эффективной реализации HTTP-кэширования.
Совместимость с браузером
На самом деле не существует единого API, называемого HTTP-кешем. Это общее название набора API-интерфейсов веб-платформы. Эти API поддерживаются во всех браузерах:
Cache-Control
ETag
Last-Modified
Как работает HTTP-кэш
Все HTTP-запросы, которые делает браузер, сначала направляются в кеш браузера, чтобы проверить, существует ли действительный кэшированный ответ, который можно использовать для выполнения запроса. Если есть совпадение, ответ считывается из кэша, что устраняет как задержку в сети, так и затраты на передачу данных, возникающие при передаче.
Поведение HTTP-кэша контролируется комбинацией заголовков запросов и заголовков ответов . В идеальном сценарии вы будете контролировать как код вашего веб-приложения (который будет определять заголовки запросов), так и конфигурацию вашего веб-сервера (который будет определять заголовки ответов).
Более подробный концептуальный обзор можно найти в статье HTTP-кэширования MDN.
Заголовки запросов: придерживайтесь значений по умолчанию (обычно).
Существует ряд важных заголовков, которые следует включать в исходящие запросы вашего веб-приложения, но браузер почти всегда заботится о том, чтобы установить их от вашего имени при отправке запросов. Заголовки запросов, влияющие на проверку актуальности, такие как If-None-Match
и If-Modified-Since
отображаются на основе понимания браузером текущих значений в HTTP-кеше.
Это хорошая новость — это означает, что вы можете продолжать включать такие теги, как <img src="my-image.png">
в свой HTML, и браузер автоматически позаботится о HTTP-кешировании за вас, без дополнительных усилий.
Заголовки ответов: настройте свой веб-сервер
Наиболее важная часть настройки HTTP-кэширования — это заголовки, которые ваш веб-сервер добавляет к каждому исходящему ответу. Следующие заголовки влияют на эффективное поведение кэширования:
-
Cache-Control
. Сервер может вернуть директивуCache-Control
чтобы указать, как и как долго браузер и другие промежуточные кэши должны кэшировать отдельный ответ. -
ETag
. Когда браузер обнаруживает кэшированный ответ с истекшим сроком действия, он может отправить на сервер небольшой токен (обычно хэш содержимого файла), чтобы проверить, изменился ли файл. Если сервер возвращает тот же токен, значит, файл тот же, и его повторно загружать не нужно. -
Last-Modified
. Этот заголовок служит той же цели, что иETag
, но использует основанную на времени стратегию для определения того, изменился ли ресурс, в отличие от стратегииETag
, основанной на контенте.
Некоторые веб-серверы имеют встроенную поддержку настройки этих заголовков по умолчанию, в то время как другие полностью оставляют заголовки, если вы не настроите их явно. Конкретные детали настройки заголовков сильно различаются в зависимости от того, какой веб-сервер вы используете, и вам следует обратиться к документации вашего сервера, чтобы получить наиболее точную информацию.
Чтобы сэкономить вам время на поиски, вот инструкции по настройке нескольких популярных веб-серверов:
Отсутствие заголовка ответа Cache-Control
не отключает кэширование HTTP! Вместо этого браузеры эффективно угадывают, какой тип поведения кэширования наиболее целесообразен для данного типа контента. Скорее всего, вам нужен больший контроль, чем он предлагает, поэтому потратьте время на настройку заголовков ответов.
Какие значения заголовка ответа следует использовать?
Существует два важных сценария, которые вам следует учитывать при настройке заголовков ответов вашего веб-сервера.
Долговременное кэширование для версионных URL-адресов.
Предположим, ваш сервер инструктирует браузеры кэшировать файл CSS на 1 год ( Cache-Control: max-age=31536000
), но ваш дизайнер только что сделал экстренное обновление, которое вам необходимо немедленно развернуть. Как уведомить браузеры об обновлении «устаревшей» кэшированной копии файла? Вы не можете, по крайней мере, без изменения URL-адреса ресурса.
После того, как браузер кэширует ответ, кешированная версия используется до тех пор, пока она не перестанет быть свежей, как это определяется max-age
или expires
, или пока она не будет удалена из кеша по какой-либо другой причине — например, когда пользователь очистит кеш браузера. В результате разные пользователи могут использовать разные версии файла при создании страницы: пользователи, которые только что получили ресурс, используют новую версию, а пользователи, которые кэшировали более раннюю (но все еще действительную) копию, используют более старую версию его. ответ.
Как получить лучшее из обоих миров: кэширование на стороне клиента и быстрые обновления? Вы меняете URL-адрес ресурса и заставляете пользователя загружать новый ответ при каждом изменении его содержимого. Обычно это делается путем внедрения отпечатка файла или номера версии в его имя, например style.x234dff.css
.
При ответе на запросы URL-адресов, которые содержат « отпечаток пальца » или информацию о версии и чье содержимое никогда не должно меняться, добавьте в свои ответы Cache-Control: max-age=31536000
.
Установка этого значения сообщает браузеру, что когда ему потребуется загрузить один и тот же URL-адрес в любое время в течение следующего года (31 536 000 секунд; максимальное поддерживаемое значение), он может немедленно использовать значение в HTTP-кэше без необходимости делать сетевой запрос для ваш веб-сервер вообще. Это здорово — вы сразу же получаете надежность и скорость, которые возникают благодаря отказу от сети!
Инструменты сборки, такие как Webpack, могут автоматизировать процесс присвоения хэш-отпечатков URL-адресам ваших ресурсов.
Повторная проверка сервера для неверсионных URL-адресов
К сожалению, не все загружаемые вами URL-адреса имеют версии. Возможно, вы не можете включить этап сборки перед развертыванием веб-приложения, поэтому вы не можете добавлять хэши к URL-адресам своих активов. И каждому веб-приложению нужны HTML-файлы — эти файлы (почти!) никогда не будут содержать информацию о версии, поскольку никто не будет использовать ваше веб-приложение, если им нужно запомнить, что URL-адрес для посещения — https://example.com/index.34def12.html
. Итак, что вы можете сделать для этих URL-адресов?
Это один из сценариев, в котором вам нужно признать поражение. HTTP-кэширование само по себе недостаточно мощно, чтобы полностью избежать сети. (Не волнуйтесь — скоро вы узнаете о сервисных работниках , которые обеспечат необходимую нам поддержку, чтобы повернуть битву в вашу пользу.) Но есть несколько шагов, которые вы можете предпринять, чтобы гарантировать, что сетевые запросы будут такими же быстрыми. и максимально эффективным.
Следующие значения Cache-Control
помогут вам точно настроить, где и как кэшируются неверсионные URL-адреса:
-
no-cache
. Это указывает браузеру, что он должен выполнять повторную проверку на сервере каждый раз перед использованием кэшированной версии URL-адреса. -
no-store
. Это дает указание браузеру и другим промежуточным кэшам (например, CDN) никогда не сохранять какую-либо версию файла. -
private
. Браузеры могут кэшировать файл, но промежуточные кэши — нет. -
public
. Ответ может быть сохранен в любом кэше.
См. Приложение: блок-схема Cache-Control
, чтобы визуализировать процесс принятия решения о том, какие значения Cache-Control
использовать. Cache-Control
также может принимать список директив, разделенных запятыми. См. Приложение: Примеры Cache-Control
.
Также может помочь установка ETag
или Last-Modified
. Как упоминалось в заголовках ответов , ETag
и Last-Modified
служат одной и той же цели: определить, нужно ли браузеру повторно загружать кэшированный файл, срок действия которого истек. Мы рекомендуем использовать ETag
поскольку он более точен.
Предположим, что с момента первоначальной выборки прошло 120 секунд, и браузер инициировал новый запрос того же ресурса. Сначала браузер проверяет HTTP-кеш и находит предыдущий ответ. К сожалению, браузер не может использовать предыдущий ответ, поскольку срок действия ответа истек. На этом этапе браузер может отправить новый запрос и получить новый полный ответ. Однако это неэффективно, поскольку, если ресурс не изменился, нет смысла загружать ту же информацию, которая уже находится в кеше!
Это проблема, для решения которой предназначены токены проверки, указанные в заголовке ETag
. Сервер генерирует и возвращает произвольный токен, который обычно представляет собой хэш или какой-либо другой отпечаток содержимого файла. Браузеру не обязательно знать, как генерируется отпечаток пальца; ему нужно только отправить его на сервер при следующем запросе. Если отпечаток остался прежним, значит ресурс не изменился и браузер может пропустить загрузку.
Установка ETag
или Last-Modified
делает запрос на повторную проверку намного более эффективным, позволяя ему запускать заголовки запроса If-Modified-Since
или If-None-Match
упомянутые в заголовках запроса .
Когда правильно настроенный веб-сервер видит эти заголовки входящих запросов, он может подтвердить, соответствует ли версия ресурса, который браузер уже имеет в своем HTTP-кеше, последней версии на веб-сервере. Если есть совпадение, сервер может ответить HTTP-ответом 304 Not Modified
, что эквивалентно «Эй, продолжай использовать то, что у тебя уже есть!» При отправке ответа такого типа требуется передать очень мало данных, поэтому обычно это намного быстрее, чем фактическая отправка обратно копии фактического запрашиваемого ресурса.
Краткое содержание
HTTP-кэш — эффективный способ повысить производительность нагрузки, поскольку он уменьшает ненужные сетевые запросы. Он поддерживается во всех браузерах и не требует особых усилий для настройки.
Следующие конфигурации Cache-Control
являются хорошим началом:
-
Cache-Control: no-cache
для ресурсов, которые необходимо проверять на сервере перед каждым использованием. -
Cache-Control: no-store
для ресурсов, которые никогда не следует кэшировать. -
Cache-Control: max-age=31536000
для ресурсов с поддержкой версий.
А заголовок ETag
или Last-Modified
может помочь вам более эффективно повторно проверять ресурсы кэша с истекшим сроком действия.
Узнать больше
Если вы хотите выйти за рамки основ использования заголовка Cache-Control
, ознакомьтесь с рекомендациями Джейка Арчибальда по кэшированию и руководством по ошибкам с максимальным возрастом .
См. раздел «Любите свой кэш» , чтобы узнать, как оптимизировать использование кэша для повторных посетителей.
Приложение: Дополнительные советы
Если у вас есть больше времени, вот дополнительные способы оптимизации использования HTTP-кеша:
- Используйте согласованные URL-адреса. Если вы размещаете один и тот же контент по разным URL-адресам, этот контент будет извлекаться и сохраняться несколько раз.
- Минимизируйте отток клиентов. Если часть ресурса (например, файл CSS) обновляется часто, а остальная часть файла — нет (например, код библиотеки), рассмотрите возможность разделения часто обновляемого кода в отдельный файл и использования стратегии кратковременного кэширования для часто обновляемых файлов. обновление кода и стратегия длительного кэширования для кода, который не меняется часто.
- Ознакомьтесь с новой директивой
stale-while-revalidate
если некоторая степень устаревания допустима в вашей политикеCache-Control
.
Приложение. Cache-Control
Приложение: примеры Cache-Control
Значение Cache-Control | Объяснение |
---|---|
max-age=86400 | Ответ может кэшироваться браузерами и промежуточными кэшами на срок до 1 дня (60 секунд x 60 минут x 24 часа). |
private, max-age=600 | Ответ может быть кэширован браузером (но не промежуточным кэшем) на срок до 10 минут (60 секунд x 10 минут). |
public, max-age=31536000 | Ответ может храниться любым кэшем в течение 1 года. |
no-store | Ответ не может быть кэширован и должен быть получен полностью при каждом запросе. |