Як ми контролюємо кешування веб-сторінок у всіх браузерах?


1552

Проведені нами дослідження показали, що не всі браузери дотримуються директив HTTP-кешу рівномірно.

З міркувань безпеки ми не хочемо , деякі сторінки в нашому додатку для кешування, коли - небудь, з допомогою веб - браузера. Це має працювати як мінімум для таких веб-переглядачів:

  • Internet Explorer 6+
  • Firefox 1.5+
  • Сафарі 3+
  • Opera 9+
  • Хром

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


Лише для ipad Safari, чи допомагає [це] [1]? [1]: stackoverflow.com/questions/24524248/…
Bakhshi

Найпростішим є використання: max-age = 10. Це не ідеально, оскільки сторінка буде кешована протягом 10 секунд. Але це найменше рішення «спагетті в заголовку». Крім того, це іноді забезпечує значне підвищення продуктивності на динамічних веб-сайтах, які використовують зворотні проксі. (Ваш повільний PHP скрипт буде викликатися один раз кожні 10 секунд , а потім буде кешувати зворотний проксі - сервер один раз за 10 секунд краще , ніж один раз на одного відвідувача.)
Hello World


3
Дякую за чудове запитання. Для цікавості, якою може бути ситуація, яка змушує вас надсилати деякі дані, не бажаючи, щоб приймач зберігав їх з "міркувань безпеки" . ви вже їх надіслали!
Бухгалтер з

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

Відповіді:


2578

Вступ

Правильний мінімальний набір заголовків, який працює для всіх згаданих клієнтів (і проксі):

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

Це Cache-Controlвідповідає специфікації HTTP 1.1 для клієнтів та проксі-серверів (і явно їх вимагають деякі клієнти поруч Expires). Розмір Pragmaспецифікації HTTP 1.0 для доісторичних клієнтів. Показник ExpiresHTTP 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 Servlet або 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.

Використання веб-API ASP.NET:

// `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, розділ 5.2.2 . Будьте обережні, якщо веб-сервер не визначає їх програмно, оскільки веб-сервер може містити деякі значення за замовчуванням.

Як правило, вам краще просто не вказувати метатеги HTML, щоб уникнути плутанини перед початківцями та покладатися на жорсткі заголовки відповідей HTTP. Крім того, спеціально ці <meta http-equiv>теги є недійсними в HTML5. Дозволені лише http-equivзначення, вказані в специфікації HTML5 .

Перевірка фактичних заголовків відповідей HTTP

Щоб перевірити одне та інше, ви можете побачити / налагодити їх у моніторі трафіку HTTP набору інструментів розробника веб-браузера. Ви можете потрапити туди, натиснувши клавішу F12 у Chrome / Firefox23 + / IE9 +, а потім відкривши панель вкладок "Мережа" або "Мережа", а потім натиснувши HTTP-запит, що цікавить, щоб розкрити всю інформацію про запит та відповідь HTTP. Нижче скріншот від Chrome:

Набір інструментів для розробників Chrome, HTTP-монітор трафіку, що показує заголовки відповідей HTTP на stackoverflow.com

Я хочу встановити ці заголовки і для завантаження файлів

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


16
Схоже, це не закінчено. Я спробував це рішення на IE 8 і виявив, що браузер завантажить кешовану версію, коли натиснеш кнопку назад.
Майк Оттум

16
Ймовірно, ваша методологія тестування була неправильною. Може, сторінка вже була в кеші? Можливо, заголовки були неправильними / відміненими? Можливо, ви переглядали неправильне прохання? Etc ..
BalusC

8
Насправді я підтверджую, що такий підхід є неповним і викликає проблеми з IE8 або, принаймні, за деяких обставин. Зокрема, використовуючи IE8 для отримання ресурсу через SSL, IE8 відмовиться отримувати ресурс вдруге (або взагалі, або після першої спроби, залежно від використовуваних заголовків). Наприклад, дивіться блог EricLaw .
хайлем

21
Я хотів би додати, що це, по суті, те, що робить Банк Америки. Якщо ви подивитеся на їхні заголовки відповідей і перекладете це в aspx, вони роблять: Response.AppendHeader ("Кеш-контроль", "немає кешу, немає магазину, необхідно повторно оновити"); Response.AppendHeader ("Закінчується термін дії", "Чт, 01 грудня 1994 16:00:00 GMT"); Думаю, якщо для них це досить добре, це для мене досить добре.
Джон

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 ці дні зовсім не існує).

Бонус: новий RFTP-кешування HTC .


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 м) ми можемо це зробити лише за допомогою 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 я б трохи змінив, щоб застосувати власні заголовки лише для тих сценаріїв, які, як ми знаємо, завантажуються динамічно / за допомогою Requjs. Припустимо, що ваші сценарії знаходяться в папці клієнта: <location path = "client"> ..... </location>
Ібрагім бен Салах,

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

27

Я виявив, що всі відповіді на цій сторінці все ще мали проблеми. Зокрема, я помітив, що жоден із них не зупинить IE8 використовувати кешовану версію сторінки, коли ви звертаєтесь до неї, натискаючи кнопку назад.

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

Кеш-контроль: без магазину
Варі: *

Для пояснення заголовка 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 запускає атрибут "persistent" (необхідний для Safari), кожен браузер, який я тестував, успішно змушує перезавантажити з сервер, коли користувач використовує кнопку "Назад".
coredumperror

1
@CoreDumpError, о, ви не повинні вважати, що JavaScript увімкнено.
Pacerier

@Pacerier На той момент, коли я писав відповідь у 2010 році, це працювало на останніх версіях Safari та Opera, і наш сервер ідентифікував себе як сервер HTTP 1.0. На жаль, у мене немає ніякого способу легко перевірити це, тому я не можу сказати нічого остаточного щодо останніх версій цих браузерів.
Chris Vasselli

Які версії браузера ви протестували?
Печер'є

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: без кешу. Якщо клієнт спілкується з сервером через захищене з'єднання (https: //) і сервер повертає заголовок Pragma: no-cache з відповіддю, Internet Explorer не кешує відповідь.
michaelok

@michaelok: Ваш посилання є дійсним, але пропускає більшу точку. Установіть правильний кеш-контроль / закінчується, і вам не потрібна прагма.
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
Це повно міфів. попередня перевірка та після перевірки є лише IE, стосується лише кешованих відповідей, а значення 0 - неоперативний. max-stale - це заголовок проксі-запиту, а не заголовок відповіді сервера. Термін дії закінчується, приймає лише одне значення. Більше одного призведе до ігнорування цього заголовка.
Корнель

1
@porneL, чи подаватимете ви конкурентну відповідь, яка правильно стосується цих міфів?
Відмінна думка

@Oddthinking, виглядає як 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 замість рядкових літералів "Кеш-контроль", "Прагма" та "Закінчується".
Віктор Шароватов

7

Ці директиви не зменшують жодного ризику для безпеки. Вони дійсно мають на меті змусити ААН оновлювати нестабільну інформацію, а не перешкоджати збереженню інформації. Дивіться подібне запитання . Принаймні, немає гарантії, що будь-які маршрутизатори, проксі-сервери тощо не будуть ігнорувати директиви кешування.

З позитивнішої уваги, політики щодо фізичного доступу до комп’ютерів, встановлення програмного забезпечення тощо можуть випереджати більшість фірм з точки зору безпеки. Якщо споживачі цієї інформації є представниками громадськості, єдине, що ви дійсно можете зробити, це допомогти їм зрозуміти, що коли інформація потрапить на їхню машину, ця машина - це їхня відповідальність, а не ваша.


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 для:

Кеш-контроль: без кешу

Старі браузери можуть ігнорувати це, якщо вони належним чином не відповідають 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
Кеш-контроль: відсутність кешу, необхідно повторно підтвердити

1
Встановлення давно останньої модифікації не впливає на кешування, окрім того, щоб дозволити кешовану відповідь використовувати довше через евристичну повторну перевірку.
EricLaw

6

Документація PHP для функції заголовка має досить повний приклад (внесений третьою стороною):

    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 як 2-й параметр, кажучи не перекривати попередні значення.
Жульєн Палард

1
@JulienPalard відповідь була відредагована після того, як я зробив свій коментар. Це все ще не має великого сенсу.
Корнель

Не надсилайте кілька заголовків кеш-керування, якщо ви хочете працювати в IE до 9-го року. НІКОЛИ не надсилайте попередньо або після перевірки. blogs.msdn.com/b/ieinternals/archive/2009/07/20/…
EricLaw

6

Якщо у вас виникають проблеми із завантаженням IE6-IE8 через SSL та кеш: заголовок без кешу (та подібні значення) з файлами MS Office, ви можете використовувати кеш: приватний, не зберігаючий заголовок та файл повернення за запитом POST. Це працює.


6

в моєму випадку я вирішую проблему в хромі з цим

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

де мені потрібно очистити вміст даних попередньої форми, коли користувачі з міркувань безпеки натискають кнопку назад


Проблема мого браузера mozilla 19.x також була вирішена фрагментом коду. autocomplete = "вимкнено". Дякую.
Сатя

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 (а також, можливо, і більш старих версіях) відображати вміст із кешу браузера при використанні кнопки "Назад" браузера. Спосіб запобігти цьому - додати порожній атрибут обробника події при завантаженні в тег 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 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 наступним чином. Я цілеспрямовано відредагував мій особистий невідповідний корисний код.

    імпорт веб
    імпортувати sys
    імпорт ОСОБИСТОСТІ

    myname = "main.py"

    URL = (
        '/', 'main_class'
    )

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

    render = web.template.render ("шаблони /", base = "макет", кеш = помилково)

    клас main_class (об'єкт):
        def GET (само):
            web.header ("Кеш-контроль", "немає кешу, немає магазину, необхідно повторно підтвердити")
            web.header ("Прагма", "без кешу")
            web.header ("Закінчується", "0")
            повернути render.main_form ()

        def POST (само):
            msg = "POSTed:"
            form = web.input (функція = None)
            web.header ("Кеш-контроль", "немає кешу, немає магазину, необхідно повторно підтвердити")
            web.header ("Прагма", "без кешу")
            web.header ("Закінчується", "0")
            return render.index_laid_out (привітання = msg + form.function)

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


Хіба це не багато разів висвітлюється у відповідях, які є на сайті роками?
Martin Tournoij

Директиви 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.