Кэширование файлов: строка запроса против последнего изменения?

Я дурачился со способами кэширования ресурсов моего сайта и заметил, что большинство сайтов, похожих на мои, используют строки запросов для переопределения кэширования (например: /css/style.css?v=124942823)

Впоследствии я заметил, что всякий раз, когда я сохранял свой файл style.css, последние измененные заголовки "обновлялись", что делало строку запроса ненужной.

Так что мне интересно

  • Почему так много веб-сайтов используют метод "строка запроса" вместо того, чтобы просто работать с последним измененным заголовком?
  • Должен ли я сбросить последний измененный заголовок и просто работать со строками запроса? (Есть ли какое-то конкретное преимущество в этом?)

Спасибо!

2 ответа

Решение

TL;DR

Почему так много веб-сайтов используют метод "строка запроса" вместо того, чтобы просто работать с последним измененным заголовком?

Изменение строки запроса изменяет URL, гарантируя, что контент "свежий".

Должен ли я сбросить последний измененный заголовок и просто работать со строками запроса?

Нет. Хотя это почти правильный ответ.


В Интернете используются три основные стратегии кэширования:

  • Нет кэширования или кэширование отключено
  • Использование проверочных / условных запросов
  • Кеширование навсегда

Чтобы проиллюстрировать все три, рассмотрим следующий сценарий:

Пользователь заходит на сайт впервые, загружает десять страниц и уходит. Каждая страница загружает один и тот же файл CSS. Для каждой из вышеуказанных стратегий кэширования, сколько запросов будет сделано?

Без кеширования: 10 запросов

В этом сценарии должно быть ясно, что на результат больше ничего не влияет, 10 запросов на файл css приведут к его отправке клиенту (браузеру) 10 раз.

преимущества

  • Контент всегда свежий
  • Никаких усилий / управления не требуется

Недостатки

  • Наименее эффективный, контент всегда передается

Запросы на валидацию: 10 запросов

Если используются Last-Modified или Etag, также будет 10 запросов. Однако 9 из них будут только заголовками, и тело не будет передано. Клиенты используют условные запросы, чтобы избежать повторной загрузки того, что уже есть. Возьмите, например, файл CSS для этого сайта.

При первом запросе файла происходит следующее:

$ curl -i http://cdn.sstatic.net/stackru/all.css
HTTP/1.1 200 OK
Server: cloudflare-nginx
Date: Mon, 12 May 2014 07:38:31 GMT
Content-Type: text/css
Connection: keep-alive
Set-Cookie: __cfduid=d3fa9eddf76d614f83603a42f3e552f961399880311549; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.sstatic.net; HttpOnly
Cache-Control: public, max-age=604800
Last-Modified: Wed, 30 Apr 2014 22:09:37 GMT
ETag: "8026e7dfc064cf1:0"
Vary: Accept-Encoding
CF-Cache-Status: HIT
Expires: Mon, 19 May 2014 07:38:31 GMT
CF-RAY: 1294f50b2d6b08de-CDG
.avatar-change:hover{backgro.....Some KB of content

Последующий запрос на тот же URL будет выглядеть так:

$ curl -i -H "If-Modified-Since:Wed, 30 Apr 2014 22:09:37 GMT" http://cdn.sstatic.net/stackru/all.css
HTTP/1.1 304 Not Modified
Server: cloudflare-nginx
Date: Mon, 12 May 2014 07:40:11 GMT
Content-Type: text/css
Connection: keep-alive
Set-Cookie: __cfduid=d0cc5afd385060dd8ba26265f0ebf40f81399880411024; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.sstatic.net; HttpOnly
Cache-Control: public, max-age=604800
Last-Modified: Wed, 30 Apr 2014 22:09:37 GMT
ETag: "8026e7dfc064cf1:0"
Vary: Accept-Encoding
CF-Cache-Status: HIT
Expires: Mon, 19 May 2014 07:40:11 GMT
CF-RAY: 1294f778e75d04a3-CDG

Обратите внимание, что тело отсутствует, и ответом является 304 Не изменено. Это говорит клиенту, что содержимое, которое у него уже есть (в локальном кеше) для этого URL, все еще свежо.

Это не значит, что это оптимальный сценарий. Использование таких инструментов, как вкладка "Сеть" в инструментах разработчика Chrome, позволяет точно определить, сколько времени и для чего требуется запрос:

Поскольку у ответа нет тела, время отклика будет намного меньше, потому что данных для передачи меньше. Но есть еще ответ. и все еще есть все накладные расходы на подключение к удаленному серверу.

преимущества

  • Контент всегда свежий
  • Отправлен только один "полный" запрос
  • Девять запросов намного меньше, содержат только заголовки
  • Более эффективным

Недостатки

  • По-прежнему выдает максимальное количество запросов
  • Все еще несет DNS поисков
  • Еще нужно установить соединение с удаленным сервером
  • Не работает в автономном режиме
  • Может потребоваться настройка сервера

Кеширование навсегда: 1 запрос

Если нет etags, нет последнего измененного заголовка и только заголовка expires, установленного далеко в будущем - только самый первый доступ к URL приведет к любой связи с удаленным сервером. Это хорошо известно? лучшая практика для лучшей производительности внешнего интерфейса. Если это так, то для последующих запросов клиент будет считывать содержимое из своего собственного кэша и вообще не связываться с удаленным сервером.

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

преимущества

  • Наиболее эффективно, контент передается только один раз

Недостатки

  • URL должен измениться, чтобы существующие посетители не загружали устаревшие кэшированные версии.
  • Больше всего усилий по настройке / управлению

Не используйте строки запроса для очистки кэша

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

Использование строк запроса предотвращает кеширование прокси-сервера. В приведенной ниже цитате автор демонстрирует, что запрос от веб-сайта браузера <-> прокси-сервер кеша <-> не использует прокси-кеш:

Загрузка mylogo.gif? V =1.2 дважды (очистка кеша между ними) приводит к следующим заголовкам:

>> GET http://stevesouders.com/mylogo.gif?v=1.2 HTTP/1.1
<< HTTP/1.0 200 OK
<< Date: Sat, 23 Aug 2008 00:19:34 GMT
<< Expires: Tue, 21 Aug 2018 00:19:34 GMT
<< X-Cache: MISS from someserver.com
<< X-Cache-Lookup: MISS from someserver.com

>> GET http://stevesouders.com/mylogo.gif?v=1.2 HTTP/1.1
<< HTTP/1.0 200 OK
<< Date: Sat, 23 Aug 2008 00:19:47 GMT
<< Expires: Tue, 21 Aug 2018 00:19:47 GMT
<< X-Cache: MISS from someserver.com
<< X-Cache-Lookup: MISS from someserver.com

Здесь ясно, что второй ответ не был обработан прокси-сервером: заголовки ответов для кэширования говорят, что MISS, значения Date и Expires изменяются, а в хвостовом журнале доступа stevesouders.com отображаются два обращения.

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

Вместо активов контроля версий

"Лучшее" решение заключается в том, чтобы файлы контроля версий были такими, чтобы при изменении содержимого каждый раз менялся и URL. Обычно это автоматизируется как часть процесса сборки.

Однако почти компромиссом является реализация правила перезаписи, такого как

# ------------------------------------------------------------------------------
# | Filename-based cache busting                                               |
# ------------------------------------------------------------------------------

# If you're not using a build process to manage your filename version revving,
# you might want to consider enabling the following directives to route all
# requests such as `/css/style.12345.css` to `/css/style.css`.

# To understand why this is important and a better idea than `*.css?v231`, read:
# http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring

<IfModule mod_rewrite.c>
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L]
</IfModule>

Таким образом, запрос на foo.123.css обрабатывается сервером как foo.css - у этого есть все преимущества использования параметра запроса для очистки кэша, но без проблемы отключения кэширования прокси.

Заголовок Last-Modified по-разному применяется во всех браузерах, но обычно браузер выдает условный запрос GET, на который сервер должен ответить, если необходимо обновить кэш. Например, в Firefox...

Заголовок ответа "Last-Modified" может использоваться как слабый валидатор. Он считается слабым, потому что имеет разрешение в 1 секунду. Если в ответе присутствует заголовок "Last-Modified", то клиент может выдать заголовок запроса "If-Modified-Since" для проверки кэшированного документа.

Когда запрос проверки сделан, сервер может либо проигнорировать запрос и ответ проверки с нормальным 200 OK, либо он может возвратить 304 Not Modified, чтобы дать указание браузеру использовать его кэшированную копию. Последний ответ также может включать заголовки, которые обновляют время истечения кэшированного документа.

Установив метку времени (или отпечаток пальца), вы явно сообщаете браузеру, когда ему необходимо обновить кэш, и затем вы можете установить очень длительное время истечения.

Возможно, стоит отметить, что в документации по конвейеру ресурсов рельсов ( http://guides.rubyonrails.org/asset_pipeline.html) есть 3 преимущества для снятия отпечатков пальцев по временной метке строки запроса:

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

Для получения более подробной информации и рекомендаций по кэшированию: https://developers.google.com/speed/docs/best-practices/caching

Другие вопросы по тегам