Как мы контролируем кэширование веб-страниц во всех браузерах?


1552

Наши исследования показали, что не все браузеры одинаково уважают директивы кеша HTTP.

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

  • Internet Explorer 6+
  • Firefox 1.5+
  • Safari 3+
  • Опера 9+
  • Хром

Наше требование пришло из теста безопасности. После выхода из нашего веб-сайта вы можете нажать кнопку «Назад» и просмотреть кэшированные страницы.


Только для ipad Safari, [this] [1] помогает? [1]: stackoverflow.com/questions/24524248/…
Бахши

Самое простое использование: max-age = 10. Это не идеально, потому что страница будет кэшироваться в течение 10 секунд. Но это наименее "спагетти" из заголовков. Кроме того, это иногда обеспечивает значительное повышение производительности на динамических веб-сайтах, которые используют обратные прокси-серверы. (Ваш медленный скрипт php будет вызываться каждые 10 секунд, а затем будет кэшироваться обратным прокси-сервером. Один раз в 10 секунд лучше, чем один раз для каждого посетителя)
Hello World


3
Спасибо за этот замечательный вопрос. Для любопытства может возникнуть ситуация, когда вы отправляете некоторые данные, но не хотите, чтобы получатель сохранял их по «соображениям безопасности» . Вы уже отправили их!
Бухгалтер م

1
@Accountant: в его сценарии пользователь вышел из системы. Кто может гарантировать, что следующим человеком-пользователем в этом User-Agent будет человек, который только что вышел из системы?
Фабьен Хаддади

Ответы:


2579

Введение

Правильный минимальный набор заголовков, который работает на всех упомянутых клиентах (и прокси):

Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0

Это Cache-Controlсоответствует спецификации HTTP 1.1 для клиентов и прокси (и неявно требуется для некоторых клиентов рядом Expires). Pragma согласно спецификации HTTP 1.0 для доисторических клиентов. Это Expiresв соответствии со спецификациями HTTP 1.0 и 1.1 для клиентов и прокси. В HTTP 1.1 Cache-Controlприоритет имеет приоритет Expires, так что это в конце концов только для прокси HTTP 1.0.

Если вас не волнует IE6 и его неправильное кэширование при обслуживании страниц только по протоколу HTTPS no-store, вы можете пропустить это Cache-Control: no-cache.

Cache-Control: no-store, must-revalidate
Pragma: no-cache
Expires: 0

Если вас не интересуют ни IE6, ни клиенты HTTP 1.0 (HTTP 1.1 был представлен в 1997 году), вы можете пропустить это Pragma.

Cache-Control: no-store, must-revalidate
Expires: 0

Если вы не заботитесь о прокси HTTP 1.0, то можете пропустить Expires .

Cache-Control: no-store, must-revalidate

С другой стороны, если сервер автоматически включает в себя действительный Dateзаголовок, то вы можете теоретически опустить Cache-Controlи полагаться наExpires только на него.

Date: Wed, 24 Aug 2016 18:32:02 GMT
Expires: 0

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

Другие Cache-Controlпараметры, такие как не max-ageимеют значения, если Cache-Controlуказаны вышеупомянутые параметры. Last-ModifiedЗаголовок, включенные в большинстве других ответов здесь только интересно , если вы на самом деле хотите , чтобы кэшировать запрос, так что вам не нужно указывать его вообще.

Как это установить?

Используя PHP:

header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1.
header("Pragma: no-cache"); // HTTP 1.0.
header("Expires: 0"); // Proxies.

Используя Java-сервлет или Node.js:

response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setHeader("Expires", "0"); // Proxies.

Использование ASP.NET-MVC

Response.Cache.SetCacheability(HttpCacheability.NoCache);  // HTTP 1.1.
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
Response.AppendHeader("Expires", "0"); // Proxies.

Использование ASP.NET Web API:

// `response` is an instance of System.Net.Http.HttpResponseMessage
response.Headers.CacheControl = new CacheControlHeaderValue
{
    NoCache = true,
    NoStore = true,
    MustRevalidate = true
};
response.Headers.Pragma.ParseAdd("no-cache");
// We can't use `response.Content.Headers.Expires` directly
// since it allows only `DateTimeOffset?` values.
response.Content?.Headers.TryAddWithoutValidation("Expires", 0.ToString()); 

Использование ASP.NET:

Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
Response.AppendHeader("Expires", "0"); // Proxies.

Использование ASP.NET Core v3

// using Microsoft.Net.Http.Headers
Response.Headers[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate";
Response.Headers[HeaderNames.Expires] = "0";
Response.Headers[HeaderNames.Pragma] = "no-cache";

Используя ASP:

Response.addHeader "Cache-Control", "no-cache, no-store, must-revalidate" ' HTTP 1.1.
Response.addHeader "Pragma", "no-cache" ' HTTP 1.0.
Response.addHeader "Expires", "0" ' Proxies.

Используя Ruby on Rails или Python / Flask:

headers["Cache-Control"] = "no-cache, no-store, must-revalidate" # HTTP 1.1.
headers["Pragma"] = "no-cache" # HTTP 1.0.
headers["Expires"] = "0" # Proxies.

Использование Python / Django:

response["Cache-Control"] = "no-cache, no-store, must-revalidate" # HTTP 1.1.
response["Pragma"] = "no-cache" # HTTP 1.0.
response["Expires"] = "0" # Proxies.

Использование Python / Pyramid:

request.response.headerlist.extend(
    (
        ('Cache-Control', 'no-cache, no-store, must-revalidate'),
        ('Pragma', 'no-cache'),
        ('Expires', '0')
    )
)

Используя Go:

responseWriter.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1.
responseWriter.Header().Set("Pragma", "no-cache") // HTTP 1.0.
responseWriter.Header().Set("Expires", "0") // Proxies.

Использование .htaccessфайла Apache :

<IfModule mod_headers.c>
    Header set Cache-Control "no-cache, no-store, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires 0
</IfModule>

Использование HTML4:

<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">

Метатеги HTML и заголовки ответа HTTP

Важно знать, что когда страница HTML обслуживается через соединение HTTP и заголовок присутствует как в заголовках ответа HTTP, так и в <meta http-equiv>тегах HTML , то заголовок, указанный в заголовке ответа HTTP, будет иметь приоритет над метатегом HTML. Метатег HTML будет использоваться только при просмотре страницы из файловой системы локального диска через file://URL. Смотрите также W3 HTML spec глава 5.2.2 . Будьте осторожны с этим, когда вы не указываете их программно, потому что веб-сервер может включать некоторые значения по умолчанию.

Как правило, лучше не указывать метатеги HTML, чтобы избежать путаницы среди начинающих и полагаться на жесткие заголовки HTTP-ответов. Более того, именно эти <meta http-equiv>теги недопустимы в HTML5. Разрешены только http-equivзначения, указанные в спецификации HTML5 .

Проверка фактических заголовков ответа HTTP

Чтобы проверить и то, и другое, вы можете увидеть / отладить их в мониторе HTTP-трафика набора инструментов разработчика веб-браузера. Для этого нажмите F12 в Chrome / Firefox23 + / IE9 +, а затем откройте панель вкладок «Сеть» или «Сеть», а затем щелкните интересующий HTTP-запрос, чтобы раскрыть все подробности о HTTP-запросе и ответе. Ниже приведен скриншот из Chrome:

Монитор HTTP-трафика набора инструментов разработчика Chrome, показывающий заголовки ответа HTTP на stackoverflow.com

Я хочу установить эти заголовки и при загрузке файлов

Прежде всего, этот вопрос и ответ нацелены на «веб-страницы» (HTML-страницы), а не на «загрузки файлов» (PDF, zip, Excel и т. Д.). Вам лучше их кэшировать и использовать какой-нибудь идентификатор версии файла где-нибудь в пути URI или строку запроса, чтобы принудительно выполнить повторную загрузку измененного файла. В любом случае, применяя эти заголовки без кэширования при загрузке файлов, остерегайтесь ошибки IE7 / 8 при обработке загрузки файлов по HTTPS вместо HTTP. Подробнее см. IE не может загрузить foo.jsf. IE не смог открыть этот интернет-сайт. Запрашиваемый сайт либо недоступен, либо не найден .


16
Это не кажется полным. Я попробовал это решение в IE 8 и обнаружил, что браузер загрузит кэшированную версию, когда вы нажмете кнопку «Назад».
Майк Оттум

16
Вероятно, ваша методика тестирования была неправильной. Может быть страница уже была в кеше? Может быть, заголовки были неверны / переопределены? Может быть, вы искали не тот запрос? И т.д ..
BalusC

8
На самом деле, я подтверждаю, что этот подход является неполным и вызывает проблемы с IE8, или, по крайней мере, при некоторых обстоятельствах. В частности, при использовании IE8 для извлечения ресурса по SSL, IE8 откажется извлекать ресурс во второй раз (либо вообще, либо после первой попытки, в зависимости от используемых заголовков). Посмотрите блог EricLaw , например.
Хайлем

21
Я хотел бы добавить, что это, по сути, то, что делает Банк Америки. Если вы посмотрите на их заголовки ответов и переведите их в aspx, они делают: Response.AppendHeader («Cache-Control», «no-cache, no-store, must-revalidate»); Response.AppendHeader («Истекает», «Четверг, 01 декабря 1994 г., 16:00:00 по Гринвичу»); Я полагаю, если это достаточно хорошо для них, это достаточно хорошо для меня.
Джон

8
@John: заголовок, срок действия которого истекает, является именно примером значения в спецификации HTTP 1.0 . Это работает, но несколько глупо использовать именно эту метку времени.
BalusC

244

(Привет всем: пожалуйста, не просто бездумно копируйте и вставляйте все заголовки, которые вы можете найти)

Прежде всего, история кнопки «Назад» не является кешем :

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

В старой спецификации HTTP формулировка была еще сильнее, явно указав браузерам игнорировать директивы кеша для истории кнопок возврата.

Назад должна вернуться назад во времени (к тому времени , когда пользователь был в системе). Он не переходит к ранее открытому URL.

Однако на практике кэш может влиять на кнопку «Назад» в очень специфических обстоятельствах:

  • Страница должна быть доставлена ​​через HTTPS , в противном случае эта очистка кэша не будет надежной. Кроме того, если вы не используете HTTPS, то ваша страница уязвима для кражи логина многими другими способами.
  • Вы должны отправить Cache-Control: no-store, must-revalidate(некоторые браузеры наблюдают, no-storeа некоторые наблюдают must-revalidate)

Вам никогда не нужно ни одного из:

  • <meta>с заголовками кэша - это не работает вообще. Совершенно бесполезно.
  • post-check/ pre-check- это директива только для IE, которая применяется только к кэшируемым ресурсам.
  • Отправка одного и того же заголовка дважды или десятком частей. Некоторые фрагменты PHP фактически заменяют предыдущие заголовки, в результате чего отправляется только последний.

Если вы хотите, вы можете добавить:

  • no-cacheили max-age=0, что сделает ресурс (URL) устаревшим и потребует, чтобы браузеры проверили с сервером, есть ли более новая версия (no-store уже подразумевает, что это еще сильнее).
  • Expiresс датой в прошлом для клиентов HTTP / 1.0 (хотя настоящие клиенты только с HTTP / 1.0 полностью отсутствуют в наши дни).

Бонус: новый HTTP-кеширование RFC .


1
Повлияет ли это на производительность сайта с точки зрения времени загрузки? как отсутствие хранилища, отсутствие кэширования и необходимость повторной проверки влияют на производительность?
Раман Гхай

@RamanGhai Отключение кэширования обычно снижает производительность (и все 3 упомянутых вами варианта отключают кэширование). Это может сделать CDN и прокси-провайдеров (например, обычно используемыми операторами мобильной связи) неэффективными. Это не повредит первой загрузке новым пользователем (кроме проблемы с прокси), но затем последующая навигация может быть намного медленнее.
Корнел

@porneL вы заявляете, что мы должны отправить Cache-Control: must-revalidate. Почему бы не отправить, Cache-Control: no-cacheпоскольку no-cacheуже подразумевается must-revalidate? w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1
Pacerier

3
@Pacerier связь no-cacheс must-revalidateверна для кеша, но обратная история не является кешем. Браузер особый случай явно must-revalidateдля управления поведением истории .
Корнель

@porneL, Хм, есть ли RFC поддержки, который утверждает, что это желаемое поведение?
Pacerier

103

Как сказал @Kornel, вам нужно не деактивировать кеш, а деактивировать буфер истории. У разных браузеров есть свои тонкие способы отключения буфера истории.

В Chrome (v28.0.1500.95 m) мы можем сделать это только путем Cache-Control: no-store.

В FireFox (v23.0.1) любой из них будет работать:

  1. Cache-Control: no-store

  2. Cache-Control: no-cache (только https)

  3. Pragma: no-cache (только https)

  4. Vary: * (только https)

В Opera (v12.15) мы можем сделать это только Cache-Control: must-revalidate(только https).

В Safari (v5.1.7, 7534.57.2) любой из них будет работать:

  1. Cache-Control: no-store
    <body onunload=""> в HTML

  2. Cache-Control: no-store (только https)

В IE8 (v8.0.6001.18702IC) любой из них будет работать:

  1. Cache-Control: must-revalidate, max-age=0

  2. Cache-Control: no-cache

  3. Cache-Control: no-store

  4. Cache-Control: must-revalidate
    Expires: 0

  5. Cache-Control: must-revalidate
    Expires: Sat, 12 Oct 1991 05:00:00 GMT

  6. Pragma: no-cache (только https)

  7. Vary: * (только https)

Объединение вышесказанного дает нам это решение, которое работает для Chrome 28, FireFox 23, IE8, Safari 5.1.7 и Opera 12.15: Cache-Control: no-store, must-revalidate (только https)

Обратите внимание, что https необходим, потому что Opera не будет отключать буфер истории для простых http-страниц. Если вы действительно не можете получить https и готовы игнорировать Opera, лучшее, что вы можете сделать, это:

Cache-Control: no-store
<body onunload="">

Ниже показаны необработанные журналы моих тестов:

HTTP:

  1. Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Opera 12.15
    Успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7

  2. Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Opera 12.15
    Успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7

  3. Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    Pragma: no-cache
    Vary: *
    Ошибка: Safari 5.1.7, Opera 12.15
    Успех: Chrome 28, FireFox 23, IE8

  4. Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    Ошибка: Safari 5.1.7, Opera 12.15
    Успех: Chrome 28, FireFox 23, IE8

  5. Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Успех: IE8

  6. Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Успех: IE8

  7. Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Успех: IE8

  8. Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Успех: IE8

  9. Cache-Control: no-store
    Ошибка: Safari 5.1.7, Opera 12.15
    Успех: Chrome 28, FireFox 23, IE8

  10. Cache-Control: no-store
    <body onunload="">
    Ошибка: Opera 12.15
    Успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7

  11. Cache-Control: no-cache
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Успех: IE8

  12. Vary: *
    Ошибка: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
    Успех: нет

  13. Pragma: no-cache
    Ошибка: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
    Успех: нет

  14. Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Успех: IE8

  15. Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Успех: IE8

  16. Cache-Control: must-revalidate, max-age=0
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Успех: IE8

  17. Cache-Control: must-revalidate
    Expires: 0
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Успех: IE8

  18. Cache-Control: must-revalidate
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Успех: IE8

  19. Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
    Успех: нет

HTTPS:

  1. Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
    Успех: нет

  2. Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
    Успех: нет

  3. Vary: *
    Ошибка: Chrome 28, Safari 5.1.7, Opera 12.15
    Успех: FireFox 23, IE8

  4. Pragma: no-cache
    Ошибка: Chrome 28, Safari 5.1.7, Opera 12.15
    Успех: FireFox 23, IE8

  5. Cache-Control: no-cache
    Ошибка: Chrome 28, Safari 5.1.7, Opera 12.15
    Успех: FireFox 23, IE8

  6. Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
    Ошибка: Chrome 28, Safari 5.1.7, Opera 12.15
    Успех: FireFox 23, IE8

  7. Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    Pragma: no-cache
    Vary: *
    Ошибка: Chrome 28, Safari 5.1.7, Opera 12.15
    Успех: FireFox 23, IE8

  8. Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    Ошибка: Chrome 28, Safari 5.1.7, Opera 12.15
    Успех: FireFox 23, IE8

  9. Cache-Control: must-revalidate
    Ошибка: Chrome 28, FireFox 23, IE8, Safari 5.1.7
    Успех: Opera 12.15

  10. Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, IE8, Safari 5.1.7
    Успех: Opera 12.15

  11. Cache-Control: must-revalidate, max-age=0
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7
    Успех: IE8, Opera 12.15

  12. Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Chrome 28, Safari 5.1.7
    Успех: FireFox 23, IE8, Opera 12.15

  13. Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Chrome 28, Safari 5.1.7
    Успех: FireFox 23, IE8, Opera 12.15

  14. Cache-Control: no-store
    Ошибка: Opera 12.15
    Успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7

  15. Cache-Control: private, no-cache, no-store, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Opera 12.15
    Успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7

  16. Cache-Control: private, no-cache, no-store, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Ошибка: Opera 12.15
    Успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7

  17. Cache-Control: private, no-cache
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    Ошибка: Chrome 28, Safari 5.1.7, Opera 12.15
    Успех: FireFox 23, IE8

  18. Cache-Control: must-revalidate
    Expires: 0
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7,
    успех: IE8, Opera 12.15

  19. Cache-Control: must-revalidate
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7,
    успех: IE8, Opera 12.15

  20. Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7,
    успех: IE8, Opera 12.15

  21. Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    <body onunload="">
    Ошибка: Chrome 28, FireFox 23, Safari 5.1.7,
    успех: IE8, Opera 12.15

  22. Cache-Control: private, must-revalidate
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    Ошибка: Chrome 28, Safari 5.1.7
    Успех: FireFox 23, IE8, Opera 12.15

  23. Cache-Control: no-store, must-revalidate
    Ошибка: нет
    Успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15


3
Я знаю, что это было опубликовано пару лет назад, но это было интересное чтение. Эта проблема сводила меня с ума уже несколько месяцев, и тело, похоже, действительно знает, как справиться с управлением кешем. Я видел несколько людей, использующих, <body onunload="">но это больше похоже на способ решения проблемы. Я попытался использовать .htaccess и изменить заголовки таким образом, если я использую HTTPS, должен ли он работать таким образом? В основном это сафари, где проблема возникает больше всего.
Джордан

4
@ Джордан, согласно журналам выше, если у вас есть HTTPS, то добавление Cache-Control: no-storeсделает свое дело. <body onunload="">нужен только тогда, когда у вас нет HTTPS.
Pacerier

37

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

<configuration>
<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Cache-Control" value="no-cache, no-store, must-revalidate" />
            <!-- HTTP 1.1. -->
            <add name="Pragma" value="no-cache" />
            <!-- HTTP 1.0. -->
            <add name="Expires" value="0" />
            <!-- Proxies. -->
        </customHeaders>
    </httpProtocol>
</system.webServer>

А вот способ Express / node.js сделать то же самое:

app.use(function(req, res, next) {
    res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
    res.setHeader('Pragma', 'no-cache');
    res.setHeader('Expires', '0');
    next();
});

Для web.config я бы немного изменил, чтобы применять пользовательские заголовки только для тех скриптов, которые, как мы знаем, загружаются динамически / с использованием requirejs. Предполагая, что ваши сценарии находятся в папке клиента: <location path = "client"> ..... </ location>
Ибрагим бен Салах,

Для кого может быть интересно, что web.confэто: Это основные настройки и файл конфигурации для ASP.NETвеб-приложения. Это документ XML, который находится в корневом каталоге. ( вики )
еще

27

Я обнаружил, что у всех ответов на этой странице все еще были проблемы. В частности, я заметил, что ни один из них не помешает IE8 использовать кэшированную версию страницы, когда вы открыли ее, нажав кнопку «Назад».

После долгих исследований и испытаний я обнаружил, что мне нужны только два заголовка:

Cache-Control: нет магазина
Варь: *

Для объяснения заголовка Vary, проверьте http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.6

В IE6-8, FF1.5-3.5, Chrome 2-3, Safari 4 и Opera 9-10 эти заголовки вызывали запрос страницы с сервера при нажатии на ссылку на страницу или указании URL-адреса. прямо в адресной строке. Это охватывает около 99% всех используемых браузеров по состоянию на январь 10 года.

В IE6 и Opera 9-10 нажатие кнопки «Назад» по-прежнему вызывало загрузку кэшированной версии. Во всех других браузерах, которые я тестировал, они получали свежую версию с сервера. До сих пор я не нашел ни одного набора заголовков, который бы заставлял эти браузеры не возвращать кэшированные версии страниц при нажатии кнопки «Назад».

Обновление: после написания этого ответа я понял, что наш веб-сервер идентифицирует себя как сервер HTTP 1.0. Заголовки, которые я перечислил, являются правильными для того, чтобы ответы от сервера HTTP 1.0 не кэшировались браузерами. Для сервера HTTP 1.1 посмотрите ответ BalusC .


4
Это работает для кнопки назад IE8! После того, как вы попробуете все в каждом другом предложении, добавление заголовка «Vary: *», по-видимому, единственное, что может заставить IE8 перезагрузить страницу, когда пользователь нажимает кнопку «Назад». И это делает работу по HTTP / 1.1 серверов.
coredumperror

В сочетании с заголовками, предложенными BarlusC, и фрагментом JS, который вызывает window.location.reload (), когда событие onPageShow срабатывает с атрибутом «persisted» (необходим для Safari), каждый браузер, который я протестировал, успешно вызывает перезагрузку из сервер, когда пользователь использует кнопку Назад.
coredumperror

1
@CoreDumpError, о, вы не должны предполагать, что JavaScript включен.
Pacerier

@Pacerier В то время, когда я писал ответ в 2010 году, это работало над последними версиями Safari и Opera, и наш сервер идентифицировал себя как сервер HTTP 1.0. К сожалению, у меня больше нет возможности легко это проверить, поэтому я не могу сказать ничего определенного о последних версиях этих браузеров.
Крис Васселли

Какие версии браузера вы тестировали?
Pacerier

21

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

В ASP.NET мы добавили их, используя следующий фрагмент:

Response.ClearHeaders(); 
Response.AppendHeader("Cache-Control", "no-cache"); //HTTP 1.1
Response.AppendHeader("Cache-Control", "private"); // HTTP 1.1
Response.AppendHeader("Cache-Control", "no-store"); // HTTP 1.1
Response.AppendHeader("Cache-Control", "must-revalidate"); // HTTP 1.1
Response.AppendHeader("Cache-Control", "max-stale=0"); // HTTP 1.1 
Response.AppendHeader("Cache-Control", "post-check=0"); // HTTP 1.1 
Response.AppendHeader("Cache-Control", "pre-check=0"); // HTTP 1.1 
Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0 
Response.AppendHeader("Expires", "Mon, 26 Jul 1997 05:00:00 GMT"); // HTTP 1.0 

Найдено по адресу : http://forums.asp.net/t/1013531.aspx


36
@bart: Еще более неприятно то, что 26 июля 1997 года была суббота, а не понедельник ...
Cᴏʀʏ

5
Cache-Control: no-cacheи Cache-Control: privateстолкновение - вы никогда не должны собирать оба вместе: первое говорит браузерам и прокси вообще не кэшировать, второе говорит прокси не кэшировать, но позволяет браузерам хранить свою собственную личную копию. Я не уверен, за какими настройками будет следовать браузер, но вряд ли он будет согласован между браузерами и версиями.
Кит

Не используйте до и после проверки. blogs.msdn.com/b/ieinternals/archive/2009/07/20/…
EricLaw

у меня это не сработало - при использовании asp.net 4.5 код запускается, но не дает требуемого результата. Я должен был следовать этому: stackoverflow.com/questions/22443932/…
Энди

8

Использование заголовка прагмы в ответе - сказка жен. RFC2616 определяет его только как заголовок запроса

http://www.mnot.net/cache_docs/#PRAGMA


4
Это хороший пример того, почему вам нужно выйти за рамки спецификаций. Если бы спецификации были кристально чистыми, для таких сайтов, как StackOverflow, не было бы особого смысла. От Microsoft В целях обратной совместимости с серверами HTTP 1.0 Internet Explorer поддерживает специальное использование заголовка HTTP Pragma: no-cache. Если клиент связывается с сервером через безопасное соединение (https: //) и сервер возвращает заголовок Pragma: no-cache с ответом, Internet Explorer не кэширует ответ.
michaelok

@michaelok: Ваша ссылка действительна, но не попадает в более крупную точку - Установите правильный Cache-Control / Expires, и вам не нужна прагма.
EricLaw

8

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я настоятельно рекомендую прочитать ответ @ BalusC. Прочитав следующий учебник по кэшированию: http://www.mnot.net/cache_docs/ (я тоже рекомендую его прочитать), я считаю, что это правильно. Тем не менее, по историческим причинам (и потому что я проверял это сам), я включу свой оригинальный ответ ниже:


Я попробовал «принятый» ответ для PHP, который не работал для меня. Затем я провел небольшое исследование, нашел небольшой вариант, проверил его, и это сработало. Вот:

header('Cache-Control: no-store, private, no-cache, must-revalidate');     // HTTP/1.1
header('Cache-Control: pre-check=0, post-check=0, max-age=0, max-stale = 0', false);  // HTTP/1.1
header('Pragma: public');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');                  // Date in the past  
header('Expires: 0', false); 
header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT');
header ('Pragma: no-cache');

Это должно работать. Проблема заключалась в том, что при установке одной и той же части заголовка дважды, если falseон не передан в качестве второго аргумента функции заголовка, функция заголовка просто перезапишет предыдущий header()вызов. Таким образом, при установке Cache-Control, например, если вы не хотите помещать все аргументы в один header()вызов функции, он должен сделать что-то вроде этого:

header('Cache-Control: this');
header('Cache-Control: and, this', false);

Смотрите более полную документацию здесь .


14
Это полно мифов. pre-check и post-check предназначены только для IE, релевантны только для кэшированных ответов, а значение 0 не используется. max-stale - заголовок запроса прокси, а не заголовок ответа сервера. Expires принимает только одно значение. Более чем один вызовет игнорирование этого заголовка.
Корнел

1
@porneL, будешь ли ты отправлять конкурирующий ответ, который правильно касается этих мифов?
Нечетное

@ Нечетное мышление, похоже на stackoverflow.com/questions/49547/… , это конкурирующий ответ.
Майк Оттум

@Pacerier да, как я уже сказал в заявлении об отказе от ответственности, воспользуйтесь ответом BalusC.
Стивен Оксли,

8

Для ASP.NET Core создайте простой класс промежуточного программного обеспечения:

public class NoCacheMiddleware
{
    private readonly RequestDelegate m_next;

    public NoCacheMiddleware( RequestDelegate next )
    {
        m_next = next;
    }

    public async Task Invoke( HttpContext httpContext )
    {
        httpContext.Response.OnStarting( ( state ) =>
        {
            // ref: http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-cached-across-all-browsers
            httpContext.Response.Headers.Append( "Cache-Control", "no-cache, no-store, must-revalidate" );
            httpContext.Response.Headers.Append( "Pragma", "no-cache" );
            httpContext.Response.Headers.Append( "Expires", "0" );
            return Task.FromResult( 0 );
        }, null );

        await m_next.Invoke( httpContext );
    }
}

затем зарегистрируйте его Startup.cs

app.UseMiddleware<NoCacheMiddleware>();

Убедитесь, что вы добавили это где-то после

app.UseStaticFiles();

Я бы предложил использовать константы из Microsoft.Net.Http.Headers.HeaderNames вместо строковых литералов "Cache-Controls", "Pragma" и "Expires".
Виктор Шароватов

7

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

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


7

В IE6 есть ошибка

Содержимое с «Content-Encoding: gzip» всегда кэшируется, даже если вы используете «Cache-Control: no-cache».

http://support.microsoft.com/kb/321722

Вы можете отключить сжатие gzip для пользователей IE6 (проверьте пользовательский агент на наличие «MSIE 6»)


6

RFC для HTTP 1.1 говорится, что правильный метод - добавить заголовок HTTP для:

Cache-Control: без кеша

Старые браузеры могут игнорировать это, если они не соответствуют должным образом HTTP 1.1. Для тех, кто может попробовать заголовок:

Прагма: без кеша

Это также должно работать для браузеров HTTP 1.1.


1
В спецификации указано, что ответ нельзя использовать повторно без повторной проверки. Это Cache-Control: no-store, который является официальным методом, чтобы указать, что ответ даже не будет сохранен в кеше.
AnthonyWJones

6

Установка модифицированного заголовка http на некоторую дату в 1995 году обычно делает свое дело.

Вот пример:

Истекает: ср, 15 ноября 1995 04:58:08 GMT
Последнее изменение: ср, 15 ноября 1995 г. 04:58:08 GMT
Cache-Control: без кеша, обязательна повторная проверка

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

6

В документации по PHP для функции header есть довольно полный пример (предоставленный третьей стороной):

    header('Pragma: public');
    header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");                  // Date in the past   
    header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT');
    header('Cache-Control: no-store, no-cache, must-revalidate');     // HTTP/1.1
    header('Cache-Control: pre-check=0, post-check=0, max-age=0', false);    // HTTP/1.1
    header ("Pragma: no-cache");
    header("Expires: 0", false);

11
Это явно неправильно. Вторые вызовы header () для Expires, Cache-control и Pragma полностью перезаписывают ранее установленные значения.
Корнел

1
@porneL: Нет, не перезаписывать ранее установленные значения, так как он передает false в качестве второго параметра, говоря, что не следует переопределять предыдущие значения.
Жюльен Палар

1
@JulienPalard ответ был отредактирован после того, как я сделал свой комментарий. Это все еще не имеет особого смысла.
Корнель

Не отправляйте несколько заголовков Cache-Control, если вы хотите работать в IE до 9. НИКОГДА не отправляйте предварительную или пост-проверку. blogs.msdn.com/b/ieinternals/archive/2009/07/20/…
EricLaw

6

Если у вас возникают проблемы с загрузкой IE6-IE8 через SSL и кеш: заголовок без кеша (и аналогичные значения) с файлами MS Office, вы можете использовать кеш: частный, заголовок без хранилища и файл возврата по запросу POST. Оно работает.


6

в моем случае я решаю проблему в Chrome с этим

<form id="form1" runat="server" autocomplete="off">

где мне нужно очистить содержимое данных прежней формы, когда пользователи нажимают кнопку назад из соображений безопасности


Моя проблема с браузером Mozilla 19.x также была исправлена ​​фрагментом кода. автозаполнения = «выключено». Спасибо.
Сатья

5

Принятый ответ не работает для IIS7 +, учитывая большое количество вопросов о том, что заголовки кэша не отправляются во II7:

И так далее

Принятый ответ правильный, в котором должны быть установлены заголовки, но не в том, как они должны быть установлены. Этот способ работает с IIS7:

Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "-1");

Первая строка устанавливает Cache-controlдля no-cache, а вторая строка добавляют другие атрибутыno-store, must-revalidate


Это работает для меня:Response.Cache.SetAllowResponseInBrowserHistory(false); Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetNoStore(); Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
Vilx-

4

Я получил лучшие и наиболее согласованные результаты во всех браузерах, установив Pragma: no-cache


4

Заголовки в ответе, предоставленном BalusC, не мешают Safari 5 (и, возможно, также более старым версиям) отображать содержимое из кэша браузера при использовании кнопки «Назад» браузера. Чтобы предотвратить это, добавьте пустой атрибут обработчика события onunload в тег body:

<body onunload=""> 

Этот взлом, по-видимому, нарушает кэш обратного просмотра в Safari: при нажатии кнопки «Назад» происходит ли событие кросс-браузерной загрузки?


Круто, я проверял это, и это на самом деле работает на Safari (5.1.7), но не на Opera.
Pacerier

4

Кроме того, просто для правильной меры, убедитесь, что вы сбросили ExpiresDefaultв своем .htaccessфайле, если вы используете это для включения кэширования.

ExpiresDefault "access plus 0 seconds"

После этого вы можете ExpiresByTypeустановить конкретные значения для файлов, которые вы хотите кэшировать:

ExpiresByType image/x-icon "access plus 3 month"

Это также может пригодиться, если ваши динамические файлы, например php и т. Д., Кэшируются браузером, и вы не можете понять, почему. Проверьте ExpiresDefault.


3

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


3
//In .net MVC
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult FareListInfo(long id)
{
}

// In .net webform
<%@ OutputCache NoStore="true" Duration="0" VaryByParam="*" %>

2

Для завершения BalusC -> ОТВЕТ Если вы используете perl, вы можете использовать CGI для добавления заголовков HTTP.

Использование Perl:

Use CGI;    
sub set_new_query() {
        binmode STDOUT, ":utf8";
        die if defined $query;
        $query = CGI->new();
        print $query->header(
                        -expires       => 'Sat, 26 Jul 1997 05:00:00 GMT',
                        -Pragma        => 'no-cache',
                        -Cache_Control => join(', ', qw(
                                            private
                                            no-cache
                                            no-store
                                            must-revalidate
                                            max-age=0
                                            pre-check=0
                                            post-check=0 
                                           ))
        );
    }

Использование apache httpd.conf

<FilesMatch "\.(html|htm|js|css|pl)$">
FileETag None
<ifModule mod_headers.c>
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</ifModule>

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


0

Я просто хочу отметить, что если кто-то хочет запретить кэширование ТОЛЬКО динамического контента, добавление этих дополнительных заголовков должно производиться программно.

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

Это совершенно очевидно, но все же стоит упомянуть.

И еще одно предупреждение. Будьте осторожны, используя метод ClearHeaders из класса HttpResponse. Это может привести к ушибам, если вы будете использовать это безрассудно. Как будто это дало мне.

После перенаправления на событие ActionFilterAttribute последствия очистки всех заголовков теряют все данные сеанса и данные в хранилище TempData. Во время перенаправления безопаснее перенаправлять из действия или не очищать заголовки.

На второй мысли я отговариваю всех использовать метод ClearHeaders. Заголовки лучше убирать отдельно. И чтобы правильно установить заголовок Cache-Control, я использую этот код:

filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");

0

Мне не повезло с <head><meta> элементами. Добавление параметров, связанных с HTTP-кешем напрямую (вне HTML-документа), действительно работает для меня.

Пример кода на Python с использованием web.headerвызовов web.py приведен ниже. Я намеренно отредактировал свой личный ненужный служебный код.

    импортировать веб
    импорт системы
    импорт ЛИЧНЫЕ КОММУНАЛЬНЫЕ ПРЕДПРИЯТИЯ

    myname = "main.py"

    URL = (
        '/', 'main_class'
    )

    main = web.application (urls, globals ())

    render = web.template.render ("templates /", base = "layout", cache = False)

    Класс main_class (объект):
        def GET (self):
            web.header («Cache-control», «no-cache, no-store, must-revalidate»)
            web.header ("Pragma", "no-cache")
            web.header («Истекает», «0»)
            вернуть render.main_form ()

        def POST (self):
            msg = "POSTed:"
            form = web.input (function = None)
            web.header («Cache-control», «no-cache, no-store, must-revalidate»)
            web.header ("Pragma", "no-cache")
            web.header («Истекает», «0»)
            вернуть render.index_laid_out (приветствие = msg + form.function)

    if __name__ == "__main__":
        nargs = len (sys.argv)
        # Убедитесь, что после имени программы Python достаточно аргументов
        если наргс! = 2
            LOG-AND-DIE ("% s: ошибка командной строки, nargs =% s, должно быть 2", myname, nargs)
        # Убедитесь, что номер порта TCP числовой
        пытаться:
            tcp_port = int (sys.argv [1])
        кроме исключения как e:
            LOG-AND-DIE («% s: tcp_port = int (% s) не удалось (не целое число)», мое имя, sys.argv [1])
        # Все хорошо!
        JUST-LOG ("% s: работает через порт% d", myname, tcp_port)
        web.httpserver.runsimple (main.wsgifunc (), ("localhost", tcp_port))
        main.run ()


Разве это не охватывается много раз уже в ответах, которые были на сайте в течение многих лет?
Мартин Турной

Директивы META работают в Internet Explorer и версиях Edge 18 и более ранних версиях. Современные браузеры их не поддерживают. crbug.com/2763
EricLaw

0

Посмотрите эту ссылку на пример кеширования:

http://securityevaluators.com/knowledge/case_studies/caching/

Резюме, согласно статье, Cache-Control: no-storeработает только на Chrome, Firefox и IE. IE принимает другие элементы управления, а Chrome и Firefox - нет. Ссылка представляет собой хорошее чтение с историей кеширования и документальным подтверждением концепции.


0

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

window.location.replace("https://www.example.com/page-not-to-be-viewed-in-browser-history-back-button.html");

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


-1

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

 <location path="index.html">
    <system.webServer>
      <httpProtocol>
        <customHeaders>
          <add name="Cache-Control" value="no-cache" />
        </customHeaders>
      </httpProtocol>
    </system.webServer>
  </location>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.