HTTP заголовок Expires. Почему браузер тем не менее обращается к серверу?

Начал серьезно интересоваться клиентской оптимизацией и натолкнулся на ситуацию с кешированием, которую я не в силах понять.

Итак, HTTP заголовок Expires.
Значение этого заголовка говорит о том, начиная с какой даты и времени документ можно считать просроченным, т.е. когда его нужно снова запрашивать у сервера или удостоверяться в его актуальности.

// Найдено тут, многие другие источники повторяют эту позицию.

Начал изучать свои сайты и столкнулся с тем, что вроде бы картинки находятся в локальном кеше и Expires установлен на пару месяцев, но Firebug и Fiddler показывают, что на них тратится время, а учитывая их большое количество (100+) и ограниченность количества потоков браузера — это время выливается в секунды. Ладно, думаю, посмотрю, как и что происходит на других, уважаемых сайтах… А там, оказывается всё так-же: запросы шлются, ответы получаются.
На главной хабра натолкнулся на такой вопиющий ужас:


Заголовки поближе:

Firebug — Net — Waiting: 12.1 s

Что же это получается? Заголовок Expires установлен на несколько месяцев вперед, т. е., по хорошему, до истечения этого срока контент в локальном кеше можно бы считать валидным и не дергать его с сервера, но по факту браузер каждый раз ходит на сервер, чтобы получить ответ 304 Not Modified. Да, заголовок ответа крошечный, но количество ресурсов, да скорость соединения, да количество параллельных потоков из браузера к домену нивелируют эту крошечность и превращают время «бесполезных» запросов в секунды.

Возникает резонный вопрос: как? Почему? И что же делать?
  • Вопрос задан
  • 27240 просмотров
Решения вопроса 1
Shedal
@Shedal
Когда вы обновляете страницу при помощи F5, браузеры обычно запрашивают у сервера, не изменились ли статические ресурсы, при помощи заголовка If-Modified-Since (что и видно на вашем скриншоте). А вот если вы откроете страницу заново, — закроете вкалдку, откроете новую и введёте адрес, — то ресурсы должны загрузиться из кэша, без round-trip'а к серверу.
Это такая специфика команды перезагрузки страницы, которую вы даёте браузеру.
Ответ написан
Пригласить эксперта
Ответы на вопрос 7
@inkvizitor68sl
Linux-сисадмин с 8 летним стажем.
F5 жать завязывайте. Вы бы ещё CTRL+F5 тыркали и жаловались, что весь контент с сервера грузится.
Для приличия — переключайтесь между двумя страницами.
Ответ написан
@1099511627776
Пишу все что интересно и на всем на чем интересно
Вы уверены что браузер ходит на сайт, а не обращается к «движку кэша» который прозрачно для него смотрит хедеры запроса и возвращает результат из кеша?
Ответ написан
@Vampiro
За время, потраченное на оформление вопроса, можно было поднять локальный сервер и посмотреть его логи. Это, имхо, один из немногих достоверных способов проверить есть запросы или нет.
Ответ написан
@Vampiro
Итак, локально.
1.html — файл без заголовков, чистая Html-Header-body-img,src=«1.php»,…
1.php — файл с таким содержимым.

header('Expires: Thu, 26 Jul 2012 05:00:00 GMT');
header('Content-type: img/png');
header('Pragma: cache');
header('Cache-Control: store, cache, no-validate');

echo file_get_contents("1.png");


Два запроса через хром к страничке.
логи сервера:
 sf.home: 127.0.0.1 [29/May/2012:00:27:55 +0400] "GET /Symfony/web/1.html HTTP/1.1" 200 230 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5"
sf.home: 127.0.0.1 [29/May/2012:00:27:55 +0400] "GET /Symfony/web/1.php HTTP/1.1" 200 80600 "http://sf.home/Symfony/web/1.html" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5"
sf.home: 127.0.0.1 [29/May/2012:00:28:07 +0400] "GET /Symfony/web/1.html HTTP/1.1" 304 - "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.52 Safari/536.5"

В консоли хрома на второй запрос к 1.php, написано:

Status Code:200 OK (from cache)
Ответ написан
Комментировать
serso
@serso
В фаербаге помимо вкладки «Заголовки»/«Headers» есть вкладка «Кеш»/«Cache». В ней отображается информация о том где хранится объект, например, для картинки с хабры я получил:

Data Size 94797
Device disk
Expires Fri May 27 2022 00:00:52 GMT+0400 (MSK)
Fetch Count 17
Last Fetched Tue May 29 2012 00:00:53 GMT+0400 (MSK)
Last Modified Tue May 29 2012 00:00:53 GMT+0400 (MSK)

HTTP заголовки хранятся только для 1ого обращения к ресурсу — для рисунка приведённого выше я имел корректные параметры Expires и браузер нормально его закешировал.

Обязательно проверьте сниффером действительно ли браузер отправляет запрос, попробуйте тоже самое в другом браузере. Если FF — то запустите его из под нового юзера, может быть у вас изменена какая-нибудь настройка.
Ответ написан
SerDIDG
@SerDIDG
Простой пример на примере моего сайта.
Без кеша:
img-fotki.yandex.ru/get/6310/9010301.4/0_719cf_b4d2aa55_orig
С кеша:
img-fotki.yandex.ru/get/6111/9010301.4/0_719d0_c1e2b15d_orig

Видно, что с кеша загрузка происходит быстрее, и скачивает с сервера намного меньше.
Ответ написан
Комментировать
Maximus43
@Maximus43
Вот что говорит гугл:
If a user agent sends a request with «Cache-Control: max-age=0» (aka. «end-to-end revalidation»), then each cache along the way will revalidate its cache entry (eg. with the «If-Not-Modified» header) all the way to the origin server. If the reply is then 304 (Not Modified), the cached entity can be used.

У вас запрос как раз с Cache-Control: max-age=0, похоже вы жмете Ctrl-F5 или браузер так обрабатывает обновление страницы.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы