В предыдущем посте мы говорили об основах клиентского кэширования. Давайте теперь взглянем на то, как работают прокси-серверы и как можно форсировать сброс клиентского кэша.
Смысл установки заголовка Expires
на далекое будущее заключается в том, чтобы браузер не перезапрашивал ресурс повторно, а загружал его из локального кэша. Таким образом, если вы как-то измените содержимое на сервере, ваши «старые» пользователи не заметят этих изменений они по-прежнему будут получать стили и скрипты из локального кэша (HTML-документы обычно не кэшируются так агрессивно).
Так что же можно сделать с этой проблемой? Как можно сообщить браузерам о необходимости обновления подобных ресурсов?
Существует два основных способа, позволяющих принудительно обновить нужное содержимое в пользовательском браузере.
styles.css -> styles.css физическое имя файла. Например:styles.css -> styles.v20091114.css
Оба способа изменяют URL файлов, тем самым вынуждая браузер загрузить его повторно.
Первый способ реализовать проще, но существует ряд важных особенностей, связанных с его использованием. Некоторые прокси-серверы не кэшируют URL содержащий GET-параметры (т.е. такие URL, как в первом примере: styles.css образом, если большое число пользователей попадает на сайт из сети, находящейся за прокси-сервером, каждый пользователь будет загружать файлы с GET-параметрами независимо, минуя кэширующий механизм прокси-сервера. Это может отразиться на скорости работы веб-сайта и даже привести к критическим ситуациям.
Но можно ли использовать второй способ так, чтобы не изменять имена файлов в файловой системе? Можно ли достичь требуемого результата, лишь изменяя HTML-код? Можно!
Веб-сервер Apache обладает мощным механизмом скрытых редиректов для локальных файлов, т.н. внутренних редиректов. Нужного эффекта можно добиться при помощи всего пары правил для всех видов кэшируемых файлов. Для второго примера, где версия файла указана после.v правила будут выглядеть следующим образом:
RewriteEngine On RewriteRule ^(.*)\.v[0-9]+\.css$ $1.css
Благодаря этим правилам запросы файлов любой версии будут перенаправляться на один и тот же их физический эквивалент. Достаточно будет лишь изменить версию файла в URL и браузеры запросят файл повторно.
Существует решение для автоматизации процесса обновления в кэше клиента всех изменившихся файлов. Но и здесь не все безоблачно.
Поскольку Web Optimizer объединяет все ресурсы в один файл, у каждого ресурса, входящего в состав итогового файла, требуется проверять атрибут mtime (время последней модификации). При наличии изменений нужно объединять ресурсы заново. Трудности, связанные с этой проверкой будут рассмотрены в другой статье, но нам важно прежде всего то, что процесс этот очень ресурсоемкий, особенно если осуществлять его при каждом запросе страницы.
Можно, однако, кэшировать все предыдущие проверки в один файл и проверять mtime только у него. Это и происходит по умолчанию проверяется время модификации единственного файла CSS или JS и в случае необходимости изменяется URL файла (добавлением GET-параметра или изменением части имени файла). Такой подход применяется для всех файлов, которые нужно кэшировать на стороне клиента. Результат будет выглядеть примерно следующим образом:
/cache/website.css видно из примера, у первого файла метка времени добавлена в качестве GET-параметра, а у второго как часть URL (которая обрабатывается при помощи правилmod_rewrite
Apache и преобразовывается в/cache/website.css
).Общая схема
Так каков же алгоритм клиентского кэширования на веб-сайте?
- Проверяем, существует ли объединенный файл. Если нет — создаем его.
- Проверяем mtime измененного файла. Если это необходимо, добавляем время модификации файла к URL (используя один из описанных выше способов).
- Браузер получает HTML-код с URL объединенного файла.
- Браузер проверяет наличие этого URL в кэше и если он существует, процесс завершается.
- В случае отсутствия URL в кэше, браузер запрашивает файл (который уже подготовлен на веб-сервере или закэширован на прокси-сервере).
Рекомендую также ознакомиться со статьей об автоматизации кэширования на webo.in.
Читать дальше