Контроль срока действия кэша с последней модификацией
В апаче mod_expires
модуль, есть Expires
директива с двумя базовыми периодами времени, доступом и модификацией.
ExpiresByType text/html "access plus 30 days"
Понятно, что кеш будет запрашивать свежий контент через 30 дней.
Тем не мение,
ExpiresByType text/html "modification plus 2 hours"
не имеет интуитивного смысла.
Как кеш браузера узнает, что файл был изменен, если он не отправляет запрос на сервер? И если он делает вызов серверу, какая польза от кэширования этой директивы? Мне кажется, что я не понимаю какую-то важную часть кеширования. Пожалуйста, просветите меня.
4 ответа
Expires*
Директива с "модификацией" в качестве основы относится ко времени модификации файла на сервере. Поэтому, если вы установите, скажем, "изменение плюс 2 часа", любой браузер, который запрашивает контент в течение 2 часов после изменения файла (на сервере), будет кэшировать этот контент в течение 2 часов после времени модификации файла. И браузер знает, когда это время, потому что сервер отправляет Expires
заголовок с надлежащим временем истечения.
Позвольте мне объяснить на примере: скажем, ваша конфигурация Apache включает в себя строку
ExpiresDefault modification plus 2 hours
и у вас есть файл index.html
, который ExpiresDefault
Директива применяется к серверу. Предположим, вы загрузили версию index.html
в 9:53 по Гринвичу, перезаписывая предыдущие существующие index.html
(если был один). Так что теперь время модификации index.html
9:53 по Гринвичу. Если вы бежали ls -l
на сервере (или dir
в Windows) вы увидите это в листинге:
-rw-r--r-- 1 apache apache 4096 Feb 18 09:53 index.html
Теперь, с каждым запросом, Apache отправляет Last-Modified
заголовок с последним временем изменения файла. Так как у вас есть это ExpiresDefault
директива, он также отправит Expires
заголовок со временем, равным времени изменения файла (9:53) плюс два часа. Итак, вот часть того, что видит браузер:
Last-Modified: Wed, 18 Feb 2009 09:53:00 GMT
Expires: Wed, 18 Feb 2009 11:53:00 GMT
Если время, в которое браузер делает этот запрос, до 11:53 по Гринвичу, браузер будет кэшировать страницу, поскольку срок ее действия еще не истек. Таким образом, если пользователь сначала посещает страницу в 11:00 по Гринвичу, а затем снова переходит на ту же страницу в 11:30 по Гринвичу, браузер увидит, что его кэшированная версия все еще действительна и не будет (или, скорее, разрешено не) сделать новый HTTP-запрос.
Если пользователь заходит на страницу в третий раз в 12:00 по Гринвичу, браузер видит, что его кэшированная версия устарела (после 11:53), поэтому он пытается проверить страницу, отправляя запрос на сервер с помощью If-Модифицированный-С заголовка. Ответ 304 (без изменений) без тела будет возвращен, поскольку дата страницы не была изменена с момента ее первого показа. Поскольку срок действия истек - страница "устарела" - запрос на проверку будет выполняться при каждом последующем посещении страницы, пока проверка не завершится неудачей.
Теперь давайте представим, что вы загрузили новую версию страницы в 11:57. В этом случае попытка браузера проверить старую версию страницы в 12:00 не удалась, и он получил в ответ вместе с новой страницей два новых заголовка:
Last-Modified: Wed, 18 Feb 2009 11:57:00 GMT
Expires: Wed, 18 Feb 2009 13:57:00 GMT
(Время последней модификации файла становится 11:57 при загрузке новой версии, и Apache рассчитывает время истечения как 11:57 + 2:00 = 13:57 по Гринвичу.)
Валидация (с использованием более поздней даты) не потребуется сейчас до 13:57.
(Обратите внимание, конечно, что многие другие вещи отправляются вместе с двумя заголовками, которые я перечислил выше, я просто обрезал все остальные для простоты)
Сервер отправляет заголовок, такой как:Last-Modified: Wed, 18 Feb 2009 00:00:00 GMT
Msgstr "Кеш ведет себя на основе этого заголовка или времени доступа.
Скажем, если контент будет обновляться каждый день, то вы хотите, чтобы срок его действия истек "модификация плюс 24 часа".
Если вы не знаете, когда будет обновлен контент, лучше основывать его на времени доступа.
Прежде всего, спасибо David Z за подробное объяснение выше. В ответ на вопрос бушмена о том, почему имеет смысл вызывать кеширование, если серверу все еще требуется сделать запрос, ответ заключается в том, что время, сэкономленное на том, что возвращает сервер, экономится. Если директивы кеша указывают, что содержимое файла все еще свежее, вместо возврата содержимого возвращается код 304 с пустым телом ответа. Вот где экономится время.
Лучшее объяснение, чем я дал, здесь: https://devcenter.heroku.com/articles/increasing-application-performance-with-http-cache-headers:
Хотя условные запросы вызывают вызов через сеть, неизмененные ресурсы приводят к пустому телу ответа, что снижает стоимость передачи ресурса обратно конечному клиенту. Бэкэнд-сервис также часто может очень быстро определить дату последнего изменения ресурса, не обращаясь к ресурсу, что экономит нетривиальное время обработки.
Время на основе
Условный запрос на основе времени гарантирует, что только если запрошенный ресурс изменился с момента кэширования копии браузера, содержимое будет передано. Если кэшированная копия является самой последней, то сервер возвращает код ответа 304.
Чтобы включить условные запросы, приложение указывает время последнего изменения ресурса через заголовок ответа Last-Modified.
Контроль кэша: общедоступный, max-age=31536000 Дата последнего изменения: Пн, 3 января 2011 17:45:57 GMT
В следующий раз, когда браузер запрашивает этот ресурс, он будет запрашивать содержимое ресурса только в том случае, если они не изменились с этой даты, используя заголовок запроса If-Modified-Since
If-Modified-Since: понедельник, 03 января 2011 17:45:57 GMT
Если ресурс не изменился с понедельника, 03 января 2011 17:45:57 GMT, сервер вернется с пустым телом с кодом ответа 304.
Насколько я понимаю, модификация просит браузер основывать время кэширования на основе значения заголовка Last-Modificatied HTTP. Таким образом, модификация плюс 2 часа будет временем последнего изменения + 2 часа.