Статические файлы (картинки, скрипты, css), как правило кешируются для более быстрой работы сайтов (уменьшение трафика - это уже скорее побочное явление). И в этом, казалось бы, нет ничего плохого. За исколючением одного - когда это самое кеширование мешает разработке. В моем случае используется стандартная связка nginx для статики + Tornado для всего остального. Но так как создавать вторую версию конфигурации nginx’а с отключенным кешированием мне не хотелось, да и в процессе разработке во многих случаях можно обойтить самим лишь Tornado, то я решил отключить кеширование в Tornado.

За отдачу статических файлов в Tornado отвечает StaticFileHandler. То логичным было предположить что кеширование отключается где-то в его настройках. Но единственное что там можно сделать, это переопределить метод get_cache_time, который и так во всех случаях возвращает 0. Исключение составляет лишь случай, когда в параметрах запроса есть ключ “v” - тогда время жизни кеша будет 10 лет.

Если посмотреть внимательно на код StaticFileHandler’а, в частности метогда, то увидем что 304-й ответ (not modified) выдаются только при соблюдении такого условия: в заголовках запроса (request headers) есть “If-Modified-Since” и время модификации файла больше, чем значение “If-Modified-Since”. Казалось бы все хорошо, но вот только дата последней модификации файла никак не может нам гарантировать, что содержимое не поменялось. В качестве значения заголовка “If-Modified-Since” браузеры передают то, что они получили от сервера на предыдущий запрос к данному ресурсу в заголовке “Last-Modified”. Таким образом для отключения кеширования статики необходимо отдать заведомо старое значение Last-Modified. Делается жто так:

 

 

Тут я указываю дату модификации на год меньше текущей даты. Так же для большей уверености выставляю значение “Expires” в 0, что сообщит браузеру о необходимости заново загрузить файл. И последнее - “Cache-Control='no-cache, must-revalidate” для большей уверенности. 

Теперь останется лишь указать наш хэндлев к как обработчик запросов к статике и все готово. А учитывая что в testing и production окружениях наверняка будет использоваться nginx, то код можно не менять, т.к. до нашего обаботчика запросы не дойдут, их обработает nginx.

Исходный код описанного хэндлера: https://github.com/e0ne/BlogSamples/blob/master/tornado-nocache/handlers.py

 


Наверняка любой разработчик, который пишет для web сталкивался с проблемой кэширования контента. При этом проблема может делится на две части: кэширование динамического контента и кэширование статического контента. Эти проблемы связанные с оптимизацией времени загрузки сайта. Я же подойду к этой проблеме с другой стороны: проблемы с кэшированием при разработке. Ведь все мы сталкивались с тем, что при изменении всего-лишь одной строке в javascript или изменении класса в CSS приходится в очередной раз очищать кэш браузера. И никакие магические сочетания Ctrl + F5 не помогают. В случае с Internet Explorer не всегда помогает даже очиситка кэша (Ctrl+R) в IE Developer Tools - приходится это делать стандартными средствами браузера.

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

Уточню, что я редко использую веб-сервер, встроенный в Visual Studio, т.к. считаю что IIS, встроенный в Windows Vista/7 более приближен к тому решению, которое будет на stage и production environments. Из этих же соображений некоторый используют Windows Server на своих рабочих станциях.

Как всегда, сначала немного теории о том, как это всё кэширование работает.

В заголовке ответа от веб-сервера (Response) может быть поле Cache-Control, которое говорит браузеру о том, как нужно кэшировать полученный файл. Самые используемые поля это:

  • no-cache - отключить кэширование;
  • max-age - максимальное время (в секундах) жизни закешированного ресурса;
  • min-fresh - минимальное время (в секундах) жизни закешированного ресурса.


Так же часто используется параметр “Expires”, который содержит дату, когда необходимо будет заново загрузить ресурс с сервера.
Подробнее о всём это можно почитать в спецификации HTTP протокола по адресу http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html.

Ещё одним способом указать браузеру, что запрашиваемый ресурс не изменился является ответ с кодом “304 Not Modified” (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html).

Таким образом, для отключения кэширования нам достаточно всегда добавлять поле no-cache в заголовок response. Побочных эффектов я тут вижу два:

  • нужно не забыть потом включить кэширование;
  • при отключенном кэшировании производительность сайта может значительно упасть, но я надеюсь, что у всех нас имеются достаточно мощные ПК для комфортной работы/разработки.

Подробно всё уже давно описано на сайтах Technet (http://technet.microsoft.com/en-us/library/cc770661(WS.10).aspx) и IIS (http://www.iis.net/ConfigReference/system.webServer/staticContent/clientCache), поэтому повторяться не буду, тем более что у меня вряд ли получится написать лучше. Скажу только пару слов о моём решении.

Кэширование я отключаю с момощью комманды “appcmd set config /section:staticContent /clientCache.cacheControlMode:DisableCache”, которую я поместил в bat-файл discache.bat.

Включаю аналогичной командой “appcmd set config /section:staticContent /clientCache.cacheControlMode:NoControl” из файла encache.bat.

Ярлыки для этих файлов можно поместить в удобное для вас место либо добавть путь к ним в переменную окружения PATH для быстрого доступа к ним из любого места. Таким образом включение/выключение кэширования происходит одним кликом/одной строчкой в командной строке и позволяет избавиться от всех проблем при активной работе с javascript, CSS и картинками.