Как контролировать кэширование веб-страниц во всех браузерах?
Наши исследования показали, что не все браузеры одинаково уважают директивы кеша 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:
Я хочу установить эти заголовки и при загрузке файлов
Прежде всего, этот вопрос и ответ нацелены на "веб-страницы" (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) любой из них будет работать:
Cache-Control: no-store
Cache-Control: no-cache
(только https)Pragma: no-cache
(только https)Vary: *
(только https)
В Opera (v12.15) мы можем сделать это только Cache-Control: must-revalidate
(только https).
В Safari (v5.1.7, 7534.57.2) любой из них будет работать:
Cache-Control: no-store
<body onunload="">
в HTMLCache-Control: no-store
(только https)
В IE8 (v8.0.6001.18702IC) любой из них будет работать:
Cache-Control: must-revalidate, max-age=0
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: must-revalidate
Expires: 0
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
(только https)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:
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.7Cache-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.7Cache-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, IE8Cache-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, IE8Cache-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
Успех: IE8Cache-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
Успех: IE8Cache-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
Успех: IE8Cache-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
Успех: IE8Cache-Control: no-store
Fail: Safari 5.1.7, Opera 12.15
Успех: Chrome 28, FireFox 23, IE8Cache-Control: no-store
<body onunload="">
Fail: Opera 12.15
Успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7Cache-Control: no-cache
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Успех: IE8Vary: *
Сбой: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Успех: нетPragma: no-cache
Сбой: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Успех: нет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
Успех: IE8Cache-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
Успех: IE8Cache-Control: must-revalidate, max-age=0
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Успех: IE8Cache-Control: must-revalidate
Expires: 0
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Успех: IE8Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Сбой: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Успех: IE8Cache-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:
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
Успех: нет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
Успех: нетVary: *
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
Успех: FireFox 23, IE8Pragma: no-cache
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
Успех: FireFox 23, IE8Cache-Control: no-cache
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
Успех: FireFox 23, IE8Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
Сбой: Chrome 28, Safari 5.1.7, Opera 12.15
Успех: FireFox 23, IE8Cache-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, IE8Cache-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, IE8Cache-Control: must-revalidate
Сбой: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Успех: Опера 12.15Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
<body onunload="">
Сбой: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Успех: Опера 12.15Cache-Control: must-revalidate, max-age=0
Ошибка: Chrome 28, FireFox 23, Safari 5.1.7
Успех: IE8, Opera 12.15Cache-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.15Cache-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.15Cache-Control: no-store
Fail: Opera 12.15
Успех: Chrome 28, FireFox 23, IE8, Safari 5.1.7Cache-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.7Cache-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.7Cache-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, IE8Cache-Control: must-revalidate
Expires: 0
Ошибка: Chrome 28, FireFox 23, Safari 5.1.7,
Успех: IE8, Opera 12.15Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Ошибка: Chrome 28, FireFox 23, Safari 5.1.7,
Успех: IE8, Opera 12.15Cache-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.15Cache-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.15Cache-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.15Cache-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:
- Expires: Mon, 26 Jul 1997 05:00:00 GMT
- Cache-Control: без кеша, приватный, обязательный переоценка, max-stale=0, post-check=0, pre-check=0 no-store
- Прагма: без кеша
В 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 определяет его только как заголовок запроса
Для 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
- IIS7: настройка кэша не работает... почему?
- Заголовки кэширования клиента IIS7 + ASP.NET MVC не работают
- Установить контроль кэша для страниц ASPX
- Контроль кэша: нет хранилища, необходимо повторное подтверждение не отправлено клиентскому браузеру в IIS7 + ASP.NET MVC
И так далее
Принятый ответ правильный, в котором должны быть установлены заголовки, но не в том, как они должны быть установлены. Этот способ работает с 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");
Конечно, это может быть невозможно реализовать на всем сайте, но, по крайней мере, для некоторых важных страниц вы можете это сделать. Надеюсь это поможет.