Ответ 1
Чтобы ответить на ваш вопрос о том, почему кэширование работает, хотя веб-сервер не включает заголовки:
- Истекает:
[a date]
- Cache-Control: max-age =
[seconds]
Сервер любезно попросил любые промежуточные прокси-серверы не кэшировать содержимое (т.е. элемент должен кэшироваться только в частном кэше, т.е. только на вашем локальном компьютере):
- Cache-Control: приватный
Но сервер забыл включить любые подсказки кэширования:
- они забыли включить Expires, поэтому браузер знает, что использовать кэшированную копию до этой даты
- они забыли включить Max-Age, поэтому браузер знает, как долго кэшируемый элемент хорош
- забыли включить E-Tag, чтобы браузер мог сделать условный запрос
Но они включили дату последнего изменения в ответ:
Last-Modified: Tue, 16 Oct 2012 03:13:38 GMT
Поскольку браузер знает дату, когда файл был изменен, он может выполнить условный запрос. Он запросит файл у сервера, но прикажет серверу отправлять файл, только если он был изменен с 2012/10/16 3:13:38:
GET / HTTP/1.1
If-Modified-Since: Tue, 16 Oct 2012 03:13:38 GMT
Сервер получает запрос, понимает, что у клиента уже самая последняя версия. Вместо того, чтобы отправить клиенту 200 OK
, а затем содержимое страницы, вместо этого он сообщает, что ваша кэшированная версия хороша:
304 Not Modified
Ваш браузер должен был перенести задержку отправки запроса на сервер и дождаться ответа, но он избавил от необходимости повторно загружать статический контент.
Почему Макс-Эйдж? Почему истекает?
Потому что Last-Modified отстой.
Не все на сервере имеют дату, связанную с ним. Если я создаю страницу на лету, с ней не связано никакой даты - это сейчас. Но я совершенно готов позволить пользователю кэшировать домашнюю страницу на 15 секунд:
200 OK
Cache-Control: max-age=15
Если пользователь забьет F5, он получит кэшированную версию в течение 15 секунд. Если это корпоративный прокси-сервер, то все 67198 пользователей, попадающих на одну и ту же страницу в одном и том же 15-секундном окне, получат одинаковое содержимое - все они будут обслуживаться из закрытого кэша. Спектакль победит всех.
Преимущество добавления Cache-Control: max-age
заключается в том, что браузер даже не должен выполнять условный запрос.
- если вы указали только
Last-Modified
, браузер должен выполнить запросIf-Modified-Since
и отслеживать ответ304 Not Modified
- если вы указали
max-age
, браузеру даже не придется страдать в сети; контент выйдет прямо из кеша
Разница между "Cache-Control: max-age" и "Expires"
Expires
является устаревшим эквивалентом современного (c. 1998) Cache-Control: max-age
заголовок Cache-Control: max-age
:
-
Expires
: вы указываете дату (гадость) -
max-age
: вы указываете секунды (доброта) -
И если оба указаны, то браузер использует
max-age
:200 OK Cache-Control: max-age=60 Expires: 20180403T192837
Любой веб-сайт, написанный после 1998 года, не должен больше использовать Expires
, а вместо этого использовать max-age
.
Что такое ETag?
ETag похож на Last-Modified, за исключением того, что он не обязательно должен быть датой - он просто должен быть чем-то.
Если я вытаскиваю список продуктов из базы данных, сервер может отправить последнюю rowversion
как ETag, а не как дату:
200 OK
ETag: "247986"
Мой ETag может быть хешем SHA1 статического ресурса (например, изображения, js, css, шрифта) или кэшированной визуализированной страницы (то есть, именно так поступает вики-сайт Mozilla MDN; они хэшируют окончательную разметку):
200 OK
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
И так же, как в случае условного запроса на основе Last-Modified:
GET / HTTP/1.1
If-Modified-Since: Tue, 16 Oct 2012 03:13:38 GMT
304 Not Modified
Я могу выполнить условный запрос на основе ETag:
GET / HTTP/1.1
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
304 Not Modified
ETag
превосходит Last-Modified
потому что он работает для вещей помимо файлов или вещей, которые имеют представление о дате. Это просто