Начинаем дружить с кешем

Или как правильно отдавать статику

If you don't clear your cache after an update - YOU GONNA HAVE A BAD TIME

О чём это?

Одним из самых значимых, на мой взгляд, плюсов реализации проекта в виде веб-приложения является простота обновления рабочей версии. Которая конечно же вытекает из клиент-серверной архитектуры. Чтобы что-то исправить вам надо просто обновить ваш сервер(а), и при следующей загрузке страницы пользователь увидит новую версию сайта.

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

Мат. часть

Под статичными файлами я, конечно-же, имею ввиду картинки, скрипты, шрифты, таблицы стилей и т.д.. Это содержимое сайта, которое не меняется в пределах одной версии проекта. В отличии от, например, html-страниц которые обычно создаются при каждом запросе клиента или от AJAX-запросов.

Сохранением данных в браузере клиента управляет HTTP-заголовок сервера Expires. В нём указывается время после которого данные необходимо считать устаревшими. Например

Expires: Thu, 15 Sep 2016 13:10:01 GMT

Недействительно после 15 сентября 2016 года 13 часов 10 минут и одной секунды. При настройке сервера это указывается в конфиге сервера как

Apache2

ExpiresDefault "access plus 10 days"

Nginx

expires 10d;

Только не спешите уменьшать это значение до предела, если Ваши клиенты начнут жаловаться, что новые возможности не появляются на вашем сайте! Давайте сначала разберёмся..

Почему кеш наш друг?

  1. Ускорение загрузки сайта
    Клиент не будет ждать получения статичных данных при загрузке второй и последующих страниц, они уже будут в его браузере
  2. Уменьшение трафика на клиенте
    Опять же, клиент меньше потратит трафика чтобы загрузить сайт. А это очень актуально для мобильных платформ!
  3. Уменьшение нагрузки на сервер
    Сервер меньше занимается чтением файлов, и больше полезной нагрузкой. Ну а если проект в облаке то это уменьшает и стоимость аренды мощностей.

Что идёт не так?

По сути, чтобы пользоваться кешем надо уметь сказать браузеру о том что версия файла изменилась. К примеру запись:

<link rel="stylesheet" href="/static/style.css">

Надо модифицировать через GET-параметр

<link rel="stylesheet" href="/static/style.css?v=1.15">

Либо сохранить версию в имени или пути файла

<link rel="stylesheet" href="/static/style.1.15.css">

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

Решение

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

Решение очень хорошо описано в документации и состоит в использовании приложения staticfiles для выставления ссылок в темплейтах, и дополнительной настройки STATICFILES_STORAGE в ManifestStaticFilesStorage или в CachedStaticFilesStorage:

# settings.py
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
# если серверный кеш настроен
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.CachedStaticFilesStorage'

Как работает

При запуске ./manage.py collectstatic ко всем статичным файлам добавится дополнительный суффикс вычисляемый динамически (md5 по контенту).

Дополнительно, создаётся файл манифеста staticfiles.json (запись в серверном кеше для CachedStaticFilesStorage), который содержит словарь соответствий оригинально имени файла к его весифицированной копии:

"/img/logo_new.png": "/img/logo_new.02d565a9c2db.png"

При создании html-страницы, если DEBUG=False, в темплейте происходит выставление имён на основе staticfiles.json. Таким образом, в момент генерации страницы сложная операция по вычислению хеша файлов не выполняется.

В продакшн!

Вот в общем-то и всё. Хочется ещё раз подчеркнуть, что решение работает "из коробки"! В лучшем случае, вам придётся заменить в темплейтах {% load static %} на {% load staticfiles %}. В худшем - убрать устаревшее {{ STATIC_URL }} или и вовсе не правильноe прямое указание пути href="/static/my_file.css", хотя это так и так лучше бы сделать..

Спасибо за внимание

Комментарии


Комментариев пока не было

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

Можете воспользоваться разметкой Markdown.

Лента комментариев

Контакты