FileETag MTime Size
Теперь Apache для генерации e-tag будет использовать только время последнего изменения и размер файла. Это, к сожалению, приводит нас к другой проблеме использования e-tag, которая тоже актуальна для if-modified-since (хоть и в меньшей степени). Поскольку e-tag зависит от времени последнего изменения, нам необходимо следить за синхронизацией. Если мы распределяем файлы по разным веб-серверам, всегда остается шанс, что на один из серверов файл попадет на секунду или две позже, чем на другой. В этом случае e-tag, сгенерированные серверами, будут отличаться. Мы можем изменить настройки так, чтобы генерировать e-tag только на основании размера файла, но это означает, что файл не обновится в браузере, если мы изменим его содержимое, а размер останется неизменным. Тоже не идеально.
Твой лучший друг кэш
Дело в том, что мы подходим к проблеме не с той стороны. Все возможные стратегии кэширования отталкиваются от того, что клиент спрашивает сервер, насколько актуальна копия, хранимая в кэше. Если бы сервер сам, без запроса, сообщал клиенту об изменениях файлов, то клиент в любой момент времени знал бы, что кэшированная копия валидна. Но веб устроен иначе — клиент запрашивает сервер, и никак иначе.
Или все же слегка иначе? Ведь перед отправкой любых JavaScript— или CSS-файлов клиент запрашивает страницу, которая на них ссылается с помощью тегов и . И мы можем использовать реакцию сервера для информирования клиентов о любых изменениях, произошедших с этими ресурсами. Звучит немного загадочно, поэтому скажу прямо: если мы будем изменять названия JavaScript— и CSS-файлов при каждом изменении их содержания, то сможем разрешить клиенту хранить их в кэше вечно (ведь содержимое файла по отдельно взятому адресу не меняется).
Если мы уверены в том, что конкретный ресурс никогда не изменится, то можем отправить несколько по-настоящему агрессивных заголовков. В PHP нам потребуется всего пара строк:
header(«Expires: „.gmdate(„D, d M Y H:i:s“, time()+315360000).“ GMT»);
header(«Cache-Control: max-age=315360000»);
Так мы говорим браузеру, что содержимое файла останется неизменным в течение десяти лет (т.е. плюс-минус 315 360 000 секунд), поэтому, единожды загрузив файл, браузер может следующие десять лет использовать локальную копию. Конечно, необязательно использовать для отправки JavaScript и CSS именно PHP. Мы перейдем к этому через несколько минут.
Ошибка на ошибке
Ручное изменение названий файлов при изменении их содержимого — опасное занятие. Что произойдет, если вы переименуете файл, но забудете переименовать шаблоны, указывающие на него? Что произойдет, если вы поменяете не все шаблоны, а только часть? Что случится, если вы измените шаблоны, но сам файл не переименуете? И наиболее вероятный вариант: что произойдет, если вы измените содержимое, но забудете переименовать файл или изменить ссылки на него? В лучшем случае, пользователи будут работать на старой версии сайта. В худшем — сайт перестанет работать совсем. В общем, ручное изменение названий — дурацкая идея.
На наше счастье, компьютеры с такими задачами — тупым повторением одних и тех же операций при совпадении определенных условий — справляются отменно.
Чтобы сделать этот процесс максимально безболезненным, следует для начала уяснить, что нам вообще не нужно переименовывать файлы. Между реальным расположением файла на диске и URL, с которого он доставляется пользователю, нет ничего общего. Так что в случае Apache мы можем использовать mod_rewrite, создав простое правило для редиректа определенных URL к нужным файлам:
RewriteEngine on
RewriteRule ^/(.*.)v[0-9.]+.(css|js|gif|png|jpg)$ /$1$2 [L]
Это правило обрабатывает все URL с указанными расширениями, которые также содержат суффикс версии. В процессе обработки правило переписывает URL так, чтобы он указывал на путь к нужному файлу (исключая при этом суффикс). Например:
foo.v2.gif foo.gif
/css/main.v1.27.css css/main.css
/javascript/md5.v6.js /javascript/md5.js
Когда это правило работает, мы можем менять URL (добавляя к нему суффикс версии), не меняя расположения файла на диске. Обнаружив, что URL изменился, браузер считает, что ему нужно обратиться к новому ресурсу.
Вы можете поинтересоваться, почему мы просто-напросто не использовали динамические ссылки (например, /css/main.css?v=4)? Дело в том, что, согласно спецификации HTTP, пользовательские агенты вообще не должны кэшировать такие URL. И хотя IE и Firefox это игнорируют, Opera и Safari точно следуют букве — поэтому, чтобы гарантировать корректную работу всех браузеров при кэшировании наших ресурсов, мы избегаем использовать динамические ссылки.
Читать дальше