Pull to refresh

Вебные хитрости: Принудительный рефреш статики

Reading time 5 min
Views 58K
Дано

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

Ситуация

Вы только что радикально переработали шаблон страницы (выровняли отбивки, поменяли цвета, прописали фоновые картинки). Получилось реально круто! Пора закачивать изменения на сервер. Вы запускаете FTP-клиента, перетаскиваете gif-ки и css-ки с левой панели на правую и, весь такой довольный, открываете вебсайт в своем любимом браузере…


«МАТЬ! Мать! мать!» — по привычке гулко отозвалось эхо.

Что за нах? Куда все съехало? Почему блоки налазят один на другой? Откуда эта синяя полоска? Что за тупорылый шрифт?

В голове взрывается мысль: «Мля, вот это вот угробище сейчас видит весь мир! Ладно, не весь, но по крайней мере та его часть, что ходит на мой сайт! Что делать, мать вашу, что делать?!».

Спокуха! Без паники. Ничего страшного не случилось. Все в порядке.

Достаньте из загашника любой залежалый браузер, которым вы не пользовались сто лет. Что там у вас, Нетшкаф? Симанки? Восьмая Опера? Неважно, пойдет. Открывайте вебсайт. Ну что, отлегло? Все выглядит, как и должно быть? Правильно. Именно так сейчас видят ваш сайт все новые посетители. А бардак в вашем любимом браузере — из-за того, что старое содержимое файла CSS сохранилось в браузерном кэше, и все те стили, над которыми вы корпели последние два дня, еще просто не добрались до вашего компа. Кстати, поправить это дело лечге легкого — достаточно просто нажать Ctrl + F5.

Другое дело, что не все посетители такие продвинутые, и есть вероятность, что кое-кто из них будет вынужден лицезреть съехавшую картинку в течение длительного времени. Прямо хоть подсказку им пиши: «Граждане, у кого сайт выглядит криво, жмите Ctrl + F5».

А может, есть способ получше? Нельзя ли как-то заставить браузер принудительно обновить кэш?

Забегая вперед, могу вас обрадовать: есть такой способ! Причем способ до безобразия простой, на сто процентов валидный и абсолютно безотказный. Впрочем, обо всем по порядку. Серьезно, так будет полезнее.

Анализ

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

Короткий ответ — нет. Но есть варианты. Которые мы сейчас и рассмотрим.

1. Заголовок HTTP Cache-Control

Теоретически можно было бы сопровождать отдаваемые с сервера статические ресурсы таким заголовком:

Cache-Control: no-cache

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

Можно указать и другое значение заголовка, например:

Cache-Control: max-age=86400

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

2. Заголовок HTTP Last-Modified

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

If-Modified-Since: Tue, 23 Jun 2009 19:12:47 GMT

И тогда сервер смотрит на дату изменения соответствующего файла, и если ничего не изменилось, отвечает кодом статуса 304. Такая схема взаимодействия несколько снижает нагрузку на сеть, но, к сожалению, не дает никакой гарантии, что браузер вообще решит поинтересоваться данным файлом.

Так как же все-таки добиться от него требуемого поведения? Для этого существует радикальное средство, а именно:

3. Переименование файла

В самом деле, если мы в теле HTML документа сошлемся на наш файл стилей по новому имени, например style1.css вместо style.css, то для браузера это будет однозначно другой ресурс, который он обязан будет пойти и забрать напрямую с сервера.

Ура! Проблема решена!

Однако не торопитесь радоваться. Переименование файла снимает одну проблему, но порождает массу других, не менее неприятных. Даже из чисто практических соображений очень неудобно иметь в составе проекта подобный «блуждающий» файл, а ведь он у нас не единственный! У нас ведь настроена среда разработки, имеется система контроля версий — и они не очень-то рассчитаны на работу с постоянно переименовываемыми файлами.

Но погодите, а что если… Что если менять не файл, а… Ну конечно! Эврика!

4. Переименование URL

Вспомните, что URL может содержать, помимо имени файла, еще кучу разных составляющих. Например, Query String — та часть, что идет после знака вопроса. Думали, это годится только для форумных движков: /index.php?showthread=1234? А вот и не угадали. Кто захочет, тот и воспользуется. Например, мы для нашего файла стилей. Как насчет прописать такую строку:

<link rel="stylesheet" href="/style.css?ver=123" type="text/css" />

Красиво? А то! Смотрим, что получается. Браузер закачивает HTML-код страницы. Видит указатель на таблицу стилей. Смотрит на URL: /style.css?ver=123. Проверяет в кэше и находит старую версию: /style.css?ver=122. Для браузера это два совершенно разных адреса, поэтому он не колеблясь выдает запрос GET на получение нового файла CSS.

Теперь в дело вступает веб-сервер. Он анализирует серверный адрес ресурса и определяет, что запрашивают статический файл style.css, а раз так, то хвостовая часть URL'а ему по барабану. Поэтому он берет и с чистой совестью отдает клиенту содержимое указанного файла — того самого, который вы только что изменили.

Телемаркет!

На самом деле данный подход можно разнообразить множеством модификаций — например, использовать еще более простой адрес вида /style.css?123, или задействовать серверный код, который будет автоматически преобразовывать дату изменения файла в строку и подставлять ее в виде хвостовика. Но это уже все детали. Главное, вы теперь знаете, как обеспечить адекватное отображение страницы после изменения стилей.

Удачи в сайтостроительстве!

Update

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

1. Некоторые браузеры (в первую очередь IE 6+) не кэшируют страницы, в УРЛе которых присутствуют переменные.

Неправда. Вполне себе кэшируют. Были отсмотрены километры логов на различных сайтах с разными конфигурациями, и я могу ответственно заявить: такого, чтобы какой-то браузер принципиально не кэшировал страницы с хвостовиком в адресе, замечено не было. Дальнейшее изучение вопроса в инете показало, что для уверенности желательно отдавать статику с явно прописанными директивами кэширования Cache-Control, и тогда вопрос практически полностью снимается.

2. Лучше модифицировать не переменную, а постоянную часть адреса URL, а для перенаправления на постоянный файл использовать mod_rewrite.

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

3. Делать все переименования в рамках процесса автоматической сборки и деплоймента проекта.

Товарищи! Эта заметка меньше всего адресована людям, участвующим в потоковой разработке вебного софта. Если у вас все настолько пучком, что сайт у вас деплоится по нажатию кнопки, такие вещи как переименование статики вам сто пудов должны быть известны.

Примечание: «Вебные хитрости» — это мини-серия, в которой я делюсь крупицами вебмастерского опыта, приобретенного за более чем пятилетнюю историю сопровождения и развития авторского проекта Английский без дураков.
Tags:
Hubs:
+1
Comments 31
Comments Comments 31

Articles