Как предотвратить запрос, который возвращает 304

Когда браузер НЕ делает запрос на сервер для файла?

Другими словами, у меня есть файл JavaScript. Его заголовок ответа HTTP имеет ETag, Cache-Control: public и Expires: Tue, 19 Jan 2038 03:14:07 GMT.

Сервер возвращает 304 после того, как кеш браузера был загрунтован.

Мой вопрос: почему браузер даже проверяет сервер и получает 304 в первую очередь? Я не хочу, чтобы браузер спрашивал, есть ли новая версия - он должен загружаться непосредственно из кеша браузера, не проверяя изменения с сервером, обслуживающим script.

Какая комбинация заголовков HTTP-ответов выполняет это?

Ответ 1

Во-первых, соответствующая спецификация HTTP RFC 7234. Если вы посмотрите на спецификацию, вы увидите две вещи:

  • Спецификация никогда ни при каких обстоятельствах не требует, чтобы кэш служил кешированной версией контента без повторной проверки. Существует множество мест, где спецификация отмечает, что кэш НЕ ДОЛЖЕН использовать кешированный контент для удовлетворения запроса, но ни один из них не указывает, что он ДОЛЖЕН сделать это, или что он НЕ ДОЛЖЕН повторить проверку. Поэтому поставщики браузеров всегда могут переоценить, если захотят.
  • Во-вторых, вы не делаете ничего плохого на своем конце. Браузеры могут кэшировать ответы и использовать эти кешированные ответы, учитывая заголовки, которые вы возвращаете. Ключевым моментом является раздел 4, где отмечено, что одним из условий для обслуживания кэшированного ответа является то, что ответ также:

    • fresh (см. раздел 4.2) или

    • Разрешено выполнять устаревание (см. раздел 4.2.4) или

    • успешно подтвержден (см. раздел 4.3).

    Поскольку вы выплевываете заголовок Expires, который далеко в будущем, и этот момент в будущем еще не достигнут, ответ "свежий", и поэтому повторная аттестация не требуется. Таким образом, вы делаете все, что спецификация предлагает вам быть на вашем месте. (Хотя использование Cache-Control: max-age=foo является более современным способом установки времени истечения кеша, чем использование заголовка Expires:.)

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

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

Я провел простой тест, в котором я создал HTML-страницу, содержащую тег <script>, указывающий на JS файл, тег <img>, указывающий на изображение, и тег <link>, указывающий на таблицу стилей CSS. Все эти файлы были размещены на сервере Apache, настроенном на обслуживание с помощью:

  • заголовок E-Tag,
  • Дата последней модификации,
  • a Cache-Control: max-age=172800 header

Естественно, что все ресурсы были загружены с использованием 200 кодов при загрузке первой страницы. После этого тестирование в Chrome или Firefox устанавливается с настройками по умолчанию, я заметил, что:

  • Если вы обновите страницу с помощью клавиши F5 или кнопки "Обновить", страница и все ресурсы будут revalidate (т.е. запрос делается сервером для каждого ресурса и возвращается 304).
  • Если вы вернетесь на страницу по ссылке или введите URL-адрес в строку URL-адреса на новой вкладке, то повторная аттестация не выполняется (т.е. никаких запросов не производится).
  • В Chrome, если вы обновляете страницу, выбирая строку URL и нажимая "Enter", сама страница обновляется, но никаких других ресурсов не происходит. В Firefox ни страница, ни ресурсы не проверяются.

Эта страница указывает, что Internet Explorer имеет такое же поведение:

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

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

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

Google и Mozilla обе имеют документацию о кешировании HTTP (я не могу найти что-либо эквивалентное на MSDN или на сайте Apple Developers), но и не указывает на наличие каких-либо конкретных заголовков кеширования, которые могут использоваться для изменения правил, которые браузер использует для выбора, когда нужно повторить проверку. То, что вы хотите сделать, просто невозможно.

Если вам действительно нужно больше контролировать это поведение, вы можете изучить кэш приложений HTML5 или перевернуть свою собственную логику кэширования, используя локальное хранилище HTML5, например basket.js.

Ответ 2

Expires: или Cache-Control: max-age= должны работать. Вы подтвердили в журналах сервера, что браузер фактически выполняет сетевые вызовы? Я обнаружил, что firebug, например, запутывает вывод, который предполагает, что вы делаете удаленные вызовы, когда вы на самом деле нажимаете на кеш.

Ответ 3

Существует правило, устанавливающее заголовок Expires более года в будущем нарушает HTTP 1.1 RFC.

Таким образом, заголовок HTTP-ответа здесь недействителен (Expires: Tue, 19 Jan 2038 03:14:07 GMT). Исправление этого может решить проблему!