Остановить браузер, чтобы HTTP-запросы на изображения, которые должны оставаться в кэше - mod_expires

После прочтения многих статей и некоторых вопросов здесь я, наконец, успешно активировал Apache mod_expires, чтобы сообщить браузеру, что он ДОЛЖЕН кэшировать изображения в течение 1 года.

<filesMatch "\.(ico|gif|jpg|png)$">
  ExpiresActive On
  ExpiresDefault "access plus 1 year"
  Header append Cache-Control "public"
</filesMatch>

И, к счастью, ответы сервера кажутся правильными:

HTTP/1.1 200 OK 
Date: Fri, 06 Apr 2012 19:25:30 GMT 
Server: Apache 
Last-Modified: Tue, 26 Jul 2011 18:50:14 GMT 
Accept-Ranges: bytes 
Content-Length: 24884 
Cache-Control: max-age=31536000, public 
Expires: Sat, 06 Apr 2013 19:25:30 GMT
Connection: close
Content-Type: image/jpeg 

Ну, я думал, что это остановит загрузку браузера и даже спросит сервер об изображениях на 1 год. Но это частично верно: вызывают , если вы закрываете и снова открываете браузер, браузер НЕ загружает изображения с сервера больше, , но браузер все еще запрашивает сервер с HTTP-запросом для каждого изображения.

Как заставить браузер перестать делать HTTP-запросы для каждого изображения? Даже если эти HTTP-запросы не сопровождаются загружаемым изображением, они по-прежнему остаются запрошенными сервером, что не требует увеличения времени ожидания и замедления отображения страницы!

Я уже сказал браузеру, что ДОЛЖЕН хранить изображения в кеше в течение 1 года! Почему браузер все еще запрашивает сервер для каждого изображения (даже если он не загружает изображение)?!


Глядя на сетевые графики в FireBug (меню FireBug > Net > Images), я вижу различные типы кэширования (я, очевидно, начал с кэша браузера, который был полностью пуст, я заставил кеш удалить в браузере с помощью "Очистить всю историю" ):

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

  • Когда я перемещаюсь по сайту и возвращаюсь на ту же страницу, изображения вообще не загружаются, а браузер НЕ запрашивает сервер для любого изображений. Это имеет смысл (и я хотел бы видеть это поведение также, когда браузер закрыт)!

  • Когда я закрою браузер и снова открою его на той же странице, глупый браузер делает любой HTTP-запрос на сервер один раз на изображение: он НЕ уменьшает изображение, но он все же делает HTTP-запрос, он, как браузер, запрашивает сервер об изображении (сервер отвечает на 200 OK). Это раздражает меня!

Я также приложил графики ниже, если вы заинтересованы:

enter image description here

enter image description here

EDIT: просто протестируйте теперь также FireFox 11.0, чтобы убедиться, что это не проблема моего FireFox 3.6, слишком старая. То же самое происходит!!! Я также тестировал сайт Google и сайт Stackoverflow, они оба отправляют Cache-Control: max-age=..., но браузер по-прежнему делает HTTP-запрос на сервер для каждого изображения после закрытия и открытия браузера снова на той же странице, после ответа сервера браузер НЕ загружает изображение (как я объяснял выше), но он по-прежнему делает проклятый запрос, который увеличивает время просмотра страницы.

EDIT2: и удаление заголовка Last-Modified, как предложено здесь, не решает проблему, это не имеет никакого значения.

Ответ 1

Вы использовали неправильный инструмент для анализа запросов.

Я бы рекомендовал действительно полезный Firefox addon Live HTTP headers, чтобы вы могли видеть, что действительно происходит в сети.

И чтобы быть уверенным, вы можете ssh/putty ваш сервер и сделать что-то вроде

tail -f /var/log/apache2/access.log

Ответ 2

Поведение, которое вы видите, предназначено (см. RFC7234 для получения дополнительной информации), указанное поведение:

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

Если браузеры не выполнили эти запросы, сервер никогда не будет уведомлен о том, что изображение было отображено пользователю. Для рекламных сетей это было бы катастрофическим. В начале рекламные сети "взломали" свой путь вокруг этого, показывая одно и то же изображение с использованием произвольно сгенерированных имен (например: "coke_ad_1_98719283719283.gif" ). Тем не менее, для интернет-провайдеров эта практика привела к значительному увеличению передачи данных, поскольку каждый из их пользователей повторно загружал эти идентичные рекламные изображения, минуя любые кеширующие/прокси-серверы, на которых работал их интернет-провайдер.

Итак, было достигнуто перемирие: браузеры всегда отправляли HTTP-запросы, даже для неэкспериментированных кешированных элементов. Серверы будут отвечать кодом HTTP 304 ( "не изменен" ). Это позволяет серверам записывать тот факт, что изображение было отображено клиенту. В результате рекламные сети вообще перестали использовать рандомизированные имена изображений для обхода сетевых кеш-серверов.

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

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

Но если вы посмотрите на другие доступные клиентские решения, которые появились вместе с html5, есть возможность предотвратить загрузку ресурсов

Ответ 3

Есть разница между "перезагрузкой" и "обновлением". Простое переключение на страницу с помощью кнопок "назад" и "вперед" обычно не инициирует новые HTTP-запросы, но, особенно, нажатие F5 на "обновление" страницы приведет к тому, что браузер дважды проверит его кеш. Это зависит от браузера, но, по-видимому, является нормой для FF и Chrome (т.е. Браузеров, которые имеют возможность легко наблюдать за своим сетевым трафиком.) Нажав F6, введите, если нужно сфокусировать адресную строку URL-адреса, а затем "пойти" на него, что должно перезагрузите страницу, но не дважды проверьте активы на странице.

Обновление: уточнение поведения обратной и прямой навигации. Он назывался "Back Back Cache" или BFCache в браузерах. Когда вы перемещаетесь с помощью кнопок "назад/вперед", цель состоит в том, чтобы показать вам точно, как страница была, когда вы видели ее на своей временной шкале. Никакие запросы сервера не выполняются при использовании back и forward, даже если заголовок кэша сервера говорит о том, что определенный элемент истек.

Если вы видите (200 OK BFCache) в своей сетевой панели разработчика, тогда сервер никогда не попадал - даже спросить, если-изменилось-с.

http://www.softwareishard.com/blog/firebug/firebug-tip-what-the-heck-is-bfcache/

Ответ 4

Если я принудительно обновляю, используя F5 или F5 + Ctrl, запрос отправляется. Однако, если я закрою браузер и снова введите URL-адрес, тогда NO reqeust будет отправлен. То, как я тестировался, если запрос отправлен или нет, был с помощью точек останова на начальном запросе на сервере, даже когда запрос не отправляется, он все еще отображается в Firebug, поскольку он проработал 7 мс, поэтому остерегайтесь этого.

Ответ 5

То, что вы здесь описываете, не отражает мой опыт. Если контент подан с директивой no-store или явным обновлением, то да, я ожидаю, что он вернется на исходный сервер, иначе он должен быть кэширован через перезапуск браузера (при условии, что он разрешен и может писать файл кеша).

Глядя на ваши водопады немного более подробно (что сложно, потому что они немного маленькие и размытые), браузер, похоже, делает именно то, что должен - он имеет записи для изображений, - но это просто загрузка с локальный кеш не с сервера происхождения - проверьте заголовок "Дата" в ответе (почему вы думаете, что он принимает миллисекунды вместо секунд?). Вот почему они окрашены по-разному.

Ответ 7

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

Используйте HTML5 локальное хранилище для кэширования изображений после их запроса в первый раз.

  • [+] Вы можете запретить отправке HTTP-запросов браузером, который в 99% вернет 304 (Not Modified), независимо от того, как сильно пользователь пытается (F5, ctrl + F5, просто пересматривая страницу и т.д.)

  • [-] Вы должны приложить дополнительные усилия для поддержки javascript для этого.

  • [-] Изображения хранятся в base64 (мы не можем хранить двоичные данные), поэтому они каждый раз декодируются на стороне клиента. Обычно это довольно быстро и не очень важно, но на клиентской стороне все еще есть дополнительное использование процессора. Его нужно иметь в виду.

  • [-] Локальное хранилище ограничено. Вы можете использовать ~ 5 мб данных для каждого домена (Примечание: base64 добавляет ~ 30% к исходному размеру изображения).

  • [?] Поддерживается большинством браузеров. http://caniuse.com/#search=localstorage

Example

Тест

Ответ 8

То, что вы видите в Chrome, не является записью фактических HTTP-запросов - это запись запросов ресурсов. Chrome делает это, чтобы показать вам, что актив фактически запрашивается на странице. Однако это мнение фактически не указывает, делается ли запрос. Если ресурс кэшируется, Chrome никогда не будет создавать базовый HTTP-запрос.

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

Чтобы увидеть фактические HTTP-запросы, вам нужно посмотреть на более низкий уровень. В некоторых браузерах это можно сделать с помощью плагина (например, Live HTTP Headers).

В действительности, однако, чтобы проверить, что запросы фактически не выполняются, вам необходимо проверить журналы своего сервера или использовать прокси-сервер отладки, такой как Charles или Fiddler. Это будет работать на уровне HTTP, чтобы убедиться, что запросы на самом деле не происходят.

Ответ 9

Проверка кэша и ответ 304

Существует несколько ситуаций, в которых Internet Explorer должен проверить, действительно ли кэшированная запись:

  • Кэшированная запись не имеет даты истечения срока действия и доступ к контенту в первый раз в сеансе браузера

  • Кэшированная запись имеет срок действия, но срок ее действия истек.

  • Пользователь запросил обновление страницы, нажав кнопку "Обновить" или нажав F5

Если кэшированная запись имеет дату последней модификации, IE отправляет ее в заголовок If-Modified-Since сообщения GET:

GET /images/logo.gif HTTP/1.1
Accept: */*
Referer: http://www.google.com/
Accept-Encoding: gzip, deflate
If-Modified-Since: Thu, 23 Sep 2004 17:42:04 GMT
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)
Host: www.google.com

Сервер проверяет заголовок If-Modified-Since и отвечает соответствующим образом. Если содержимое не было изменено с указанной даты/времени, оно отвечает кодом состояния 304 и ответным сообщением, которое содержит только заголовки:

HTTP/1.1 304 Not Modified
Content-Type: text/html
Server: GWS/2.1
Content-Length: 0
Date: Thu, 04 Oct 2004 12:00:00 GMT

Ответ можно быстро загрузить, поскольку он не содержит содержимого и заставляет IE читать данные, необходимые ему из кеша. По сути, это похоже на перенаправление локального кеша браузера.

Если запрашиваемый объект действительно изменился со времени даты/времени в заголовке If-Modified-Since, ответы сервера содержат код состояния 200 и передает измененную версию ресурса.

Ответ 10

Этот вопрос лучше отвечает здесь на сайте обмена веб-мастерами.

Дополнительная информация, которая также цитируется в приведенной выше ссылке, находится на httpwatch

Согласно статье:

Существует несколько ситуаций, в которых Internet Explorer должен проверить, действительно ли кэшированная запись:

  • Кэшированная запись не имеет даты истечения срока действия, и содержимое просматривается в первый раз в сеансе браузера.
  • Кэшированная запись имеет срок годности, но срок ее действия истек.
  • Пользователь запросил обновление страницы, нажав кнопку "Обновить" или нажав F5

    введите здесь код