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

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

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

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

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

26 ответов

Решение

Вступление

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

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:

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.

Используя Apache .htaccess файл:

<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, так и в HTML. <meta http-equiv> теги, то тот, который указан в заголовке ответа 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 на stackru.com

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

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

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

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

Модель свежести (раздел 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.

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

В 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="">
    Fail: 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="">
    Fail: 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: *
    Fail: 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: *
    Fail: 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
    Fail: Safari 5.1.7, Opera 12.15
    Успех: Chrome 28, FireFox 23, IE8

  10. Cache-Control: no-store
    <body onunload="">
    Fail: 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
    Успех: Опера 12.15

  10. Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
    <body onunload="">
    Сбой: Chrome 28, FireFox 23, IE8, Safari 5.1.7
    Успех: Опера 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
    Fail: 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="">
    Fail: 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="">
    Fail: 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

Я нашел маршрут 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();
});

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

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

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

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

В 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.

After a bit of research we came up with the following list of headers that seemed to cover most browsers:

В 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

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

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

Для 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://stackru.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();

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

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

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

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

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я настоятельно рекомендую прочитать ответ @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);

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

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

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

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

Вот пример:

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

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

В документации по 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);

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

Cache-Control: без кеша

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

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

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

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

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

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

Принятый ответ не работает для 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

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

ExpiresDefault "access plus 0 seconds"

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

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

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

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

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

<body onunload=""> 

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

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

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

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

Для завершения 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, браузеры игнорировали их и кэшировали страницу.

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

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

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

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

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

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

    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")
            return 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])
        кроме исключения как е:
            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()

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

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

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

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

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

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

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

Я решил таким образом.

2 соображения:

1) события на стороне сервера не запускаются при обратном щелчке вместо javascript.

2) у меня есть 2 JavaScript для чтения / записи файлов cookie

function setCookie(name, value, days)
{
    var expires = "";
    if (days)
    {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        expires = "; expires=" + date.toUTCString();
    }
    document.cookie = name + "=" + (value || "") + expires + "; path=/";
}

function getCookie(name)
{
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');

    for (var i = ca.length - 1; i >= 0; i--)
    {
        var c = ca[i];
        while (c.charAt(0) == ' ')
        {
            c = c.substring(1, c.length);
        }

        if (c.indexOf(nameEQ) == 0)
        {
            return c.substring(nameEQ.length, c.length);
        }
    }
    return null;
}

в моей Page_Load я вставил это: (это НЕ запускается при обратном щелчке)

    protected void Page_Load(object sender, EventArgs e)
    {
       Page.RegisterClientScriptBlock("", "<script>setCookie('" + Session.SessionID + "', '" + Login + "', '100');</script>");
    }

где "Логин" - это значение моего идентификатора, равное -1 после выхода из системы (вы можете использовать что-нибудь еще, например, логическое значение).

затем на моей странице я добавил это: (этот IS запускается при обратном нажатии)

<script type="text/javascript">
if (getCookie('<%= Session.SessionID %>') < 0)
        {
            if (history.length > 0)
            {
                history.go(+1);
            }
        }

</script>

ничего больше.

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

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

 <location path="index.html">
    <system.webServer>
      <httpProtocol>
        <customHeaders>
          <add name="Cache-Control" value="no-cache" />
        </customHeaders>
      </httpProtocol>
    </system.webServer>
  </location>

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

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

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

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