How do we control web page caching, across all browsers?
Asked Answered
A

30

1894

Our investigations have shown us that not all browsers respect the HTTP cache directives in a uniform manner.

For security reasons we do not want certain pages in our application to be cached, ever, by the web browser. This must work for at least the following browsers:

  • Internet Explorer 6+
  • Firefox 1.5+
  • Safari 3+
  • Opera 9+
  • Chrome

Our requirement came from a security test. After logging out from our website you could press the back button and view cached pages.

Allege answered 8/9, 2008 at 12:8 Comment(7)
Just for ipad Safari, Does [this][1] help? [1]: stackoverflow.com/questions/24524248/…Archegonium
The simplest is using: max-age=10 . This is not perfect because the page will be cached for 10 seconds. But it's the least "header spaghetti" solution out there. Also, this sometimes provides a big performance boost on dynamic websites who use reverse proxies. (Your slow php script will be called once every 10 seconds and will then be cached by the reverse proxy. once per 10 seconds is way better than once per visitor)Madder
Also see securityevaluators.com/knowledge/case_studies/cachingOuthouse
Thank you for that great question . For curiosity what might be the situation that makes you send some data while don't want the receiver to save it for "security reasons" . you sent them already!Montmartre
see https://mcmap.net/q/18344/-what-39-s-the-difference-between-cache-control-max-age-0-and-no-cacheLumper
@Accountantم, they may be concerned about input fields. Back button would normally preserve those.Annular
@Accountant: in his scenario, the user had logged out. Who can guarantee that the next human user on that User-Agent will be the person who just logged out?Atonality
H
3145

Introduction

The correct minimum set of headers that works across all mentioned clients (and proxies):

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

The Cache-Control is per the HTTP 1.1 spec for clients and proxies (and implicitly required by some clients next to Expires). The Pragma is per the HTTP 1.0 spec for prehistoric clients. The Expires is per the HTTP 1.0 and 1.1 specs for clients and proxies. In HTTP 1.1, the Cache-Control takes precedence over Expires, so it's after all for HTTP 1.0 proxies only.

If you don't care about IE6 and its broken caching when serving pages over HTTPS with only no-store, then you could omit Cache-Control: no-cache.

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

If you don't care about IE6 nor HTTP 1.0 clients (HTTP 1.1 was introduced in 1997), then you could omit Pragma.

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

If you don't care about HTTP 1.0 proxies either, then you could omit Expires.

Cache-Control: no-store, must-revalidate

On the other hand, if the server auto-includes a valid Date header, then you could theoretically omit Cache-Control too and rely on Expires only.

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

But that may fail if e.g. the end-user manipulates the operating system date and the client software is relying on it.

Other Cache-Control parameters such as max-age are irrelevant if the abovementioned Cache-Control parameters are specified. The Last-Modified header as included in most other answers here is only interesting if you actually want to cache the request, so you don't need to specify it at all.

How to set it?

Using PHP:

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

Using Java Servlet, or 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.

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

Using 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()); 

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

Using 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";

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

Using Ruby on Rails:

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

Using Python/Flask:

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

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

Using Python/Pyramid:

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

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

Using Clojure (require Ring utils):

(require '[ring.util.response :as r])
(-> response
  (r/header "Cache-Control" "no-cache, no-store, must-revalidate")
  (r/header "Pragma" "no-cache")
  (r/header "Expires" 0))

Using Apache .htaccess file:

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

Using Firebase Hosting firebase.json:

"headers": [
    { "key": "Cache-Control", "value": "no-cache, no-store, must-revalidate" },
    { "key": "Pragma", "value": "no-cache" },
    { "key": "Expires", "value": "0" }
]

Using HTML:

<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 meta tags vs HTTP response headers

Important to know is that when an HTML page is served over an HTTP connection, and a header is present in both the HTTP response headers and the HTML <meta http-equiv> tags, then the one specified in the HTTP response header will get precedence over the HTML meta tag. The HTML meta tag will only be used when the page is viewed from a local disk file system via a file:// URL. See also W3 HTML spec chapter 5.2.2. Take care with this when you don't specify them programmatically because the webserver can namely include some default values.

Generally, you'd better just not specify the HTML meta tags to avoid confusion by starters and rely on hard HTTP response headers. Moreover, specifically those <meta http-equiv> tags are invalid in HTML5. Only the http-equiv values listed in HTML5 specification are allowed.

Verifying the actual HTTP response headers

To verify the one and the other, you can see/debug them in the HTTP traffic monitor of the web browser's developer toolset. You can get there by pressing F12 in Chrome/Firefox23+/IE9+, and then opening the "Network" or "Net" tab panel, and then clicking the HTTP request of interest to uncover all detail about the HTTP request and response. The below screenshot is from Chrome:

Chrome developer toolset HTTP traffic monitor showing HTTP response headers on stackoverflow.com

I want to set those headers on file downloads too

First of all, this question and answer are targeted on "web pages" (HTML pages), not "file downloads" (PDF, zip, Excel, etc). You'd better have them cached and make use of some file version identifier somewhere in the URI path or query string to force a redownload on a changed file. When applying those no-cache headers on file downloads anyway, then beware of the IE7/8 bug when serving a file download over HTTPS instead of HTTP. For detail, see IE cannot download foo.jsf. IE was not able to open this internet site. The requested site is either unavailable or cannot be found.

Huynh answered 8/9, 2008 at 12:9 Comment(55)
This does not appear to be complete. I tried this solution on IE 8 and found that the browser will load a cached version when you hit the back button.Pallas
Likely your testing methodology was wrong. Maybe the page was already in the cache? Maybe the headers were incorrect/overriden? Maybe you were looking at the wrong request? Etc..Huynh
@BalusC: Some people told me setting expires to 0 won't work in some cases, so better set it to past date. also i got some interesting comment in php.netConglutinate
I would like to add that I just did this and it did not appear to be working while I was testing. Turned out iis on the server was caching the pagesBaseburner
Actually, I confirm that this approach is incomplete and causes issues with IE8, or at least in some circumstances. Specifically, when using IE8 to fetch a resource over SSL, IE8 will refuse to fetch the resource a second time (either at all, or after a first try, depending on headers used). See EricLaw's blog, for instance.Anxiety
@Anxiety IE6, 7 and 8 must have no-store before no-cache and can't have a Pragma header on HTTPS connections.Chute
I'd like to add that this is essentially what Bank of America does. If you look at their response headers and translate that into aspx, they're doing: Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); Response.AppendHeader("Expires", "Thu, 01 Dec 1994 16:00:00 GMT"); I figure, if it's good enough for them, it's good enough for me.Bellyband
@John: That expires header is exactly the example value in HTTP 1.0 specification. It works, but it's somewhat ridiculous to take exactly that timestamp.Huynh
Yeah, it's very arbitrary but Bank of America uses that value! lol I suppose it really doesn't matter what you use, right? But I posted the comment not to suggest any changes to your example, but to provide a real world example that supports your example from people we trust to know about this stuff (our banks).Bellyband
The "plain HTML way" you mentioned doesn't work actually, even without proxies; the headers should be in the actual HTTP headers (E.g. "Expires: 0"), not in HTML <head> tag. And when proxies get in the way, it's guaranteed not to work: proxies rely on HTTP headers, not HTML contents. I recommend reading this document to get a good understanding: mnot.net/cache_docsFullfaced
@Luka: as stated in the answer: "The HTML meta tag will only be used when the page is viewed from local disk file system."Huynh
Agreed, but the way the answer is formulated is confusing. "then the one specified in the response header will get precedence over the HTML meta tag." - when served over HTTP, META tags won't have any precedence at all. Moreover, the proxy may not read the <head> and <meta> tags at all. Finally, there are people who won't read further after they find the <meta> syntax. And then, a HTML file from local file system wouldn't change (unless on a developer machine) and thus won't need cache-control, so using the META cache-control tags are extremely uncommon (I think a small note nearby will do).Fullfaced
@Anxiety You're right: this solution completely fails to force IE8 to reload the page when the user presses the back button. Considering the documentation given by Microsoft, though, this is probably an IE8 bug (it doesn't happen in IE9), so we're highly unlikely to ever see a solution.Salient
@CoreDumpError: note that haylem's comment concerns downloading files via IE8 which is answered here. This is further unrelated to "this solution".Huynh
this might sound like a poor question . Are we supposed to write this in every page we don't want to be cached ? If I write this in jsp pages , should I write in meta tags or using response.setHeader() ?Copeck
@Raman: Do not repeat code nor write Java code in JSP. Use a filter.Huynh
@BalusC, doesn't no-cache already imply must-revalidate? And doesn't no-store already imply no-cache? Why can't we simply do Cache-Control:no-store instead of the longer version you showed in the answer?Outhouse
@Pacerier: you're right, but browsers not. The intent is to cover all browsers, also those who are wrong.Huynh
@BalusC, so are you suggesting we do some rojak like https://mcmap.net/q/18172/-how-do-we-control-web-page-caching-across-all-browsers ?Outhouse
@BalusC, your solution doesn't work on Safari 5.1.7 and OperaOuthouse
@Chute this is wrong, IE 8 can accept Pragma over HTTPS, but just not no-cache stackoverflow.com/questions/3415370/…Preamble
@RobertChrist we found that it had to have no-store before no-cache and no Pragma - when we added the Pragma IE6&7 broke under HTTPS. As Pragma's only needed by IE5 and older it's pretty pointless, so we didn't test IE8 specifically. Best practice is probably to just skip it, as (unless you support 90's browsers) it's just a waste of bytes.Chute
OMG I cannot believe this has been voted up so much. 'Pragma: No-cache' is MEANINGLESS when sent from the server to the client. 'no-store' does NOT prevent in-memory caching. 'The HTML meta tag will only be used when the page is viewed from local disk' - is wrong too. PLEASE READ THE DOCUMENTS YOU LINKED, BalusCFeigin
@Feigin I think the new wording in HTTPbis is sufficiently strong enough to prevent people from doing in-memory HTTP caching when no-store is present tools.ietf.org/html/… The browser may keep it as history, but it should never re-serve it in response to a request.Culliton
Actually, this list is not complete. The correct set would be: Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate Pragma: no-cache, no-store Expires: -1 Last-Modified: -1Station
@Chameera: Cache-control:proxy-revalidate is only relevant when you have accidentally cached the resources before by a stupid mistake and they meander around in proxies. You can safely remove this later. Pragma doesn't support no-store, this is specific to cache-control. Last-Modified is still irrelevant in this case. The -1 instead of 0 absolutely doesn't make sense and may possibly make things worse. The list in the answer is definitely complete if you start off the smart way.Huynh
@BalusC, you're right, I slipped on the Pragma. It only supports no-cache, thanks for the pointer. On the other hand, Anyone who does not want to take a risk should go with proxy-revalidate. Plus, if I'm not mistaken, the -1 is specific to UNIX and will return the minimum possible date. Far better than hard-coding some day in the past, IMHO.Station
@Chameera: the proxy-revalidate is only to fix your own mistake. Just do it right from the beginning on! The -1 is riskful because browsers may not expect a hyphen and/or a negative date and potentially cause an integer undeflow (and thus you effectively end up with max date). Just follow the instructions given in the current answer instead of unnecessarily tying to make it overcomplicated. This is almost ridiculous.Huynh
@hvgotcodes: It seems to be interfering with Firefox 31. My approach is to set a small max-age, e.g. max-age = 10. This seems to make the appcache manifest work as expected on all browsers.Madder
Shouldn't "Expires" be a date (the same value as the "Date" header), not the number "0"? See mnot.net/cache_docsRubadub
@Luke: An invalid format will be interpreted as "in the past". See also HTTP header field spec: "HTTP/1.1 clients and caches MUST treat other invalid date formats, especially including the value "0", as in the past (i.e., "already expired").".Huynh
I can't define Pragma: no-cache on Amazon S3, do you know why? Does it work without Pragma: no-cache too?Whenever
unfortunately, the w3c validator flags the html solution as an error (not warning). there must be some html solution that does not invalidate the html...Sanfordsanfourd
@ivoWelch: it's indeed not allowed anymore in HTML5. Just use response headers as recommended in answer.Huynh
Isn't pragma a request header?Twickenham
@Christoph: from your link: "HTTP/1.1 clients and caches MUST treat other invalid date formats, especially including the value "0", as in the past (i.e., "already expired")" (see also my comment-reply on his comment).Huynh
@Huynh are the HTTP headers required on every page or just the index page?Accusatorial
Technically, sending Expires: 0 is not RFC-compliant. It says that caches must interpret it as "expired", but it does not say that you as the server are allowed to send malformed dates for this purpose. It even recommends that you send Expires/Date headers with the same value to mark it expired.Krp
This page from Oracle states "Note: Never use Expires = 0 to prevent caching. The Expires header is sent by the remote server and passed through to the browser by the Portal Server. Unless the time on all three machines is synchronized, an Expires=0 header can mistakenly return cached content. To solve this problem, set the Expires header to a fixed date that is definitely in the past.". This seems to contradict most answers/comments (and the RFC). Is that something to be considered?Heaume
This helped me in making Jquery Ajax call without adding time stamp to the get urlHuebner
Forgive me for my ignorance, will this not cache the html response only, but allow updates on the css/js? That is to say if the html has script/link-css elements, it will still get them? I would not like to re-load the whole of bootstrap/jQuery at each page reloadMelleta
@Melleta They are in first place not requested by the same request as the HTML page. They are requested by their own requests which of course have their own responses as well.Huynh
That's what I figured, but wanted to make sure. Specially since I'll probably deal with it on a global-filter basisMelleta
Could someone tell me how to fix this in Django? Everything I tried doesn't work for SafariShela
In ASP.NET would code be put in Page_Load or Page_Init?Helvetii
The following post was helpful to me - I've used a combination of this answer and that one: stackoverflow.com/questions/24604921/…Her
This is the most detailed answer on a question that is really tricky. Thank you!Aerometeorograph
@Anxiety Thanks for sharing that blog post, but the primary source is now gone. I found it on the Internet Archive Wayback Machine: web.archive.org/web/20150722044610/http://blogs.msdn.com/b/…Stertor
Thanks for the great answer! I am dealing with client-side development (JS && HTML), I put <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"> in the head of html file, but not working, wonder why. I am using local file, does it work in local file? Thank you!Goetz
@James: check the section titled HTML meta tags vs HTTP response headers.Huynh
@BalusC, thanks for the response. I check that section for serveral , but still confused. The HTML meta tag will only be used when the page is viewed from a local disk file system via a file:// UR it states that meta tag will only work with local file and I am using local file, but how doesn't it work? Thanks you!Goetz
@James: continue reading .. "Moreover, specifically those <meta http-equiv> tags are invalid in HTML5. Only the http-equiv values listed in HTML5 specification are allowed."Huynh
@BalusC,sorry, forgot to check it. So it is impossible for me to clear cashe in js In HTML5 the http-equiv list in HTML5 doc seems not includes the any of them. Is it correct? OR is there ways I could do it without changing the url?Thank you so much and forgive my ignoranceGoetz
Hi, a little confused with the answer. You stated that <meta http-equiv> tags are invalid in HTML5., but what will be the correct way to prevent cache in html5 or client-side html?Provide
Kick ass answer. I just want to add that, for ASP.NET MVC, this can be applied globally by creating a custom ActionFilterAttribute that does exactly that and registering that ActionFilterAttribute in FilterConfig. This allows not to have to write this for every single page.Geyser
K
286

(hey, everyone: please don't just mindlessly copy&paste all headers you can find)

First of all, Back button history is not a cache:

The freshness model (Section 4.2) does not necessarily apply to history mechanisms. That is, a history mechanism can display a previous representation even if it has expired.

In the old HTTP spec, the wording was even stronger, explicitly telling browsers to disregard cache directives for back button history.

Back is supposed to go back in time (to the time when the user was logged in). It does not navigate forward to a previously opened URL.

However, in practice, the cache can influence the back button, in very specific circumstances:

  • Page must be delivered over HTTPS, otherwise, this cache-busting won't be reliable. Plus, if you're not using HTTPS, then your page is vulnerable to login stealing in many other ways.
  • You must send Cache-Control: no-store, must-revalidate (some browsers observe no-store and some observe must-revalidate)

You never need any of:

  • <meta> with cache headers — it doesn't work at all. Totally useless.
  • post-check/pre-check — it's an IE-only directive that only applies to cachable resources.
  • Sending the same header twice or in dozen parts. Some PHP snippets out there actually replace previous headers, resulting in only the last one being sent.

If you want, you could add:

  • no-cache or max-age=0, which will make resource (URL) "stale" and require browsers to check with the server if there's a newer version (no-store already implies this even stronger).
  • Expires with a date in the past for HTTP/1.0 clients (although real HTTP/1.0-only clients are completely non-existent these days).

Bonus: The new HTTP caching RFC.

Kentiga answered 30/3, 2011 at 23:8 Comment(7)
will this have any side-effect on the performance of the website in terms of loading time ? how no-store , no-cache , must-revalidate affect performance ?Copeck
@RamanGhai Disabling cache generally hurts performance (and all 3 options you've mentioned disable caching). It may make CDNs and ISP proxies (e.g. commonly used by mobile operators) ineffective. It doesn't hurt first load by a new user (aside from the proxy issue), but then subsequent navigation may be a lot slower.Kentiga
@porneL you state that we must send Cache-Control: must-revalidate. Why not send Cache-Control: no-cache since no-cache already implies must-revalidate? w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1Outhouse
@Outhouse the relationship of no-cache with must-revalidate is true for cache, but back history is not a cache. Browsers special-case explicit must-revalidate to control history behavior.Kentiga
@porneL, Hmm is there a supporting RFC that states that's the desired behavior?Outhouse
@porneL, I've just tested your solution (https + must-revalidate). It works on Opera but not Chrome, IE, Safari, FireFox....Outhouse
Despite MDN and Google saying otherwise, 'no-store' does not currently prevent back button caching in Chrome v90. I had to use 'no-cache, no-store'. I wasted hours trying 'no-store' by itself.Oberland
O
129

As @Kornel stated, what you want is not to deactivate the cache, but to deactivate the history buffer. Different browsers have their own subtle ways to disable the history buffer.

In Chrome (v28.0.1500.95 m) we can do this only by Cache-Control: no-store.

In FireFox (v23.0.1) any one of these will work:

  1. Cache-Control: no-store

  2. Cache-Control: no-cache (https only)

  3. Pragma: no-cache (https only)

  4. Vary: * (https only)

In Opera (v12.15) we only can do this by Cache-Control: must-revalidate (https only).

In Safari (v5.1.7, 7534.57.2) any one of these will work:

  1. Cache-Control: no-store
    <body onunload=""> in html

  2. Cache-Control: no-store (https only)

In IE8 (v8.0.6001.18702IC) any one of these will work:

  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 only)

  7. Vary: * (https only)

Combining the above gives us this solution which works for Chrome 28, FireFox 23, IE8, Safari 5.1.7, and Opera 12.15: Cache-Control: no-store, must-revalidate (https only)

Note that https is needed because Opera wouldn't deactivate history buffer for plain http pages. If you really can't get https and you are prepared to ignore Opera, the best you can do is this:

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

Below shows the raw logs of my tests:

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
    Success: 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
    Success: 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
    Success: 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
    Success: 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="">
    Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Success: 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="">
    Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Success: 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="">
    Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Success: 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="">
    Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Success: IE8

  9. Cache-Control: no-store
    Fail: Safari 5.1.7, Opera 12.15
    Success: Chrome 28, FireFox 23, IE8

  10. Cache-Control: no-store
    <body onunload="">
    Fail: Opera 12.15
    Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7

  11. Cache-Control: no-cache
    Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Success: IE8

  12. Vary: *
    Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
    Success: none

  13. Pragma: no-cache
    Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
    Success: none

  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="">
    Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Success: 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="">
    Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Success: IE8

  16. Cache-Control: must-revalidate, max-age=0
    Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Success: IE8

  17. Cache-Control: must-revalidate
    Expires: 0
    Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Success: IE8

  18. Cache-Control: must-revalidate
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
    Success: IE8

  19. Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
    Pragma: no-cache
    Vary: *
    <body onunload="">
    Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
    Success: none

HTTPS:

  1. Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    <body onunload="">
    Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
    Success: none

  2. Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    <body onunload="">
    Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
    Success: none

  3. Vary: *
    Fail: Chrome 28, Safari 5.1.7, Opera 12.15
    Success: FireFox 23, IE8

  4. Pragma: no-cache
    Fail: Chrome 28, Safari 5.1.7, Opera 12.15
    Success: FireFox 23, IE8

  5. Cache-Control: no-cache
    Fail: Chrome 28, Safari 5.1.7, Opera 12.15
    Success: FireFox 23, IE8

  6. Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
    Fail: Chrome 28, Safari 5.1.7, Opera 12.15
    Success: FireFox 23, IE8

  7. Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    Pragma: no-cache
    Vary: *
    Fail: Chrome 28, Safari 5.1.7, Opera 12.15
    Success: 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: *
    Fail: Chrome 28, Safari 5.1.7, Opera 12.15
    Success: FireFox 23, IE8

  9. Cache-Control: must-revalidate
    Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7
    Success: Opera 12.15

  10. Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
    <body onunload="">
    Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7
    Success: Opera 12.15

  11. Cache-Control: must-revalidate, max-age=0
    Fail: Chrome 28, FireFox 23, Safari 5.1.7
    Success: 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="">
    Fail: Chrome 28, Safari 5.1.7
    Success: 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="">
    Fail: Chrome 28, Safari 5.1.7
    Success: FireFox 23, IE8, Opera 12.15

  14. Cache-Control: no-store
    Fail: Opera 12.15
    Success: 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
    Success: 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
    Success: 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: *
    Fail: Chrome 28, Safari 5.1.7, Opera 12.15
    Success: FireFox 23, IE8

  18. Cache-Control: must-revalidate
    Expires: 0
    Fail: Chrome 28, FireFox 23, Safari 5.1.7,
    Success: IE8, Opera 12.15

  19. Cache-Control: must-revalidate
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Fail: Chrome 28, FireFox 23, Safari 5.1.7,
    Success: IE8, Opera 12.15

  20. Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
    Expires: 0
    <body onunload="">
    Fail: Chrome 28, FireFox 23, Safari 5.1.7,
    Success: 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="">
    Fail: Chrome 28, FireFox 23, Safari 5.1.7,
    Success: IE8, Opera 12.15

  22. Cache-Control: private, must-revalidate
    Expires: Sat, 12 Oct 1991 05:00:00 GMT
    Pragma: no-cache
    Vary: *
    Fail: Chrome 28, Safari 5.1.7
    Success: FireFox 23, IE8, Opera 12.15

  23. Cache-Control: no-store, must-revalidate
    Fail: none
    Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15

Outhouse answered 29/8, 2013 at 16:50 Comment(2)
I know this was posted a couple years back but it was an interesting read. This problem has been driving me crazy for a few months now, body seems to really know how to deal with cache control. I have seen a few people using the <body onunload=""> but it seems more like a way around the actual problem. I've tried using the .htaccess and modifying the headers that way, if I use HTTPS should it work that way? It's mainly safari where the problem arrises most.Thelmathem
@Jordan, Per the logs above if you have HTTPS then adding Cache-Control: no-store would do the trick. <body onunload=""> is only needed when you don't have HTTPS.Outhouse
S
51

I found the web.config route useful (tried to add it to the answer but doesn't seem to have been accepted so posting here)

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

And here is the express / node.js way of doing the same:

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();
});
Sunstroke answered 15/6, 2012 at 2:40 Comment(2)
For web.config I would modify just a bit to apply the custom headers only for those scripts which we know are loaded dynamically / using requirejs. Assuming your scripts are found in client folder: <location path="client"> ..... </location>Revivify
For who is may wondering what web.conf is: It is the main settings and configuration file for an ASP.NET web application. It is an XML document that resides in the root directory. (wiki).Paulettapaulette
P
39

I found that all of the answers on this page still had problems. In particular, I noticed that none of them would stop IE8 from using a cached version of the page when you accessed it by hitting the back button.

After much research and testing, I found that the only two headers I really needed were:

Cache-Control: no-store
Vary: *

For an explanation of the Vary header, check out http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.6

On IE6-8, FF1.5-3.5, Chrome 2-3, Safari 4, and Opera 9-10, these headers caused the page to be requested from the server when you click on a link to the page, or put the URL directly in the address bar. That covers about 99% of all browsers in use as of Jan '10.

On IE6, and Opera 9-10, hitting the back button still caused the cached version to be loaded. On all other browsers I tested, they did fetch a fresh version from the server. So far, I haven't found any set of headers that will cause those browsers to not return cached versions of pages when you hit the back button.

Update: After writing this answer, I realized that our web server is identifying itself as an HTTP 1.0 server. The headers I've listed are the correct ones in order for responses from an HTTP 1.0 server to not be cached by browsers. For an HTTP 1.1 server, look at BalusC's answer.

Pseudocarp answered 14/1, 2010 at 23:35 Comment(6)
This works for IE8's back button!! AFter trying everything in every other suggestion, adding the "Vary: *" header is apparently the only thing that can force IE8 to reload the page when the user presses the back button. And this does work on HTTP/1.1 servers.Salient
Combined with the headers suggested by BarlusC, plus a JS snippet that calls window.location.reload() when the onPageShow event triggers with the "persisted" attribute (needed for Safari), every browser I've tested successfully forces a reload from the server when the user uses the Back button.Salient
@CoreDumpError, oh you should not assume JavaScript is enabled.Outhouse
@Outhouse At the time I wrote the answer in 2010, this worked on what were then the latest versions of both Safari and Opera, with our server identifying itself as an HTTP 1.0 server. Unfortunately, I don't have any way to easily test this anymore, so I can't say anything definitive about the latest versions of these browsers.Pseudocarp
What were the browser versions you tested with?Outhouse
According to what I wrote then, it looks like I tested IE6 through 8, FF1.5 through 3.5, Chrome 2 and 3, Safari 4, and Opera 9 and 10.Pseudocarp
A
29

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

In ASP.NET we added these using the following snippet:

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", "Sat, 26 Jul 1997 05:00:00 GMT"); // HTTP 1.0 

Found from: http://forums.asp.net/t/1013531.aspx

Allege answered 8/9, 2008 at 12:11 Comment(4)
@bart: Even more troublesome yet is that the 26th of July in 1997 was a Saturday, not a Monday...Savill
Cache-Control: no-cache and Cache-Control: private clash - you should never get both together: the former tells browsers and proxies not to cache at all, the latter tells proxies not to cache but lets browsers hold their own private copy. I'm not sure which setting the browser will follow, but it's unlikely to be consistent between browsers and versions.Chute
Do not use pre-check and post-check. blogs.msdn.com/b/ieinternals/archive/2009/07/20/…Bandaranaike
this didn't work for me - using asp.net 4.5 the code runs but does't produce the required result. I had to follow this: stackoverflow.com/questions/22443932/…Alithia
I
11

The use of the pragma header in the response is a wives tale. RFC2616 only defines it as a request header

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

Infantile answered 17/9, 2008 at 14:18 Comment(2)
This is a good example of why you need to go beyond the specs. If the specs were always crystal clear, there wouldn't be much point for sites like StackOverflow. From Microsoft For purposes of backward compatibility with HTTP 1.0 servers, Internet Explorer supports a special usage of the HTTP Pragma: no-cache header. If the client communicates with the server over a secure connection (https://) and the server returns a Pragma: no-cache header with the response, Internet Explorer does not cache the response.Avatar
@michaelok: Your reference is valid, but misses the larger point-- Set a proper Cache-Control/Expires and you don't need pragma.Bandaranaike
G
10

There's a bug in IE6

Content with "Content-Encoding: gzip" is always cached even if you use "Cache-Control: no-cache".

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

You can disable gzip compression for IE6 users (check the user agent for "MSIE 6")

Gastroenterostomy answered 13/6, 2013 at 15:23 Comment(0)
P
10

For ASP.NET Core, create a simple middleware class:

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: https://mcmap.net/q/18172/-how-do-we-control-web-page-caching-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 );
    }
}

then register it with Startup.cs

app.UseMiddleware<NoCacheMiddleware>();

Make sure you add this somewhere after

app.UseStaticFiles();
Philomena answered 19/5, 2016 at 19:55 Comment(1)
I would suggest to use constants from Microsoft.Net.Http.Headers.HeaderNames instead of string literals "Cache-Controls", "Pragma" and "Expires".Chronoscope
A
8

DISCLAIMER: I strongly suggest reading @BalusC's answer. After reading the following caching tutorial: http://www.mnot.net/cache_docs/ (I recommend you read it, too), I believe it to be correct. However, for historical reasons (and because I have tested it myself), I will include my original answer below:


I tried the 'accepted' answer for PHP, which did not work for me. Then I did a little research, found a slight variant, tested it, and it worked. Here it is:

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');

That should work. The problem was that when setting the same part of the header twice, if the false is not sent as the second argument to the header function, header function will simply overwrite the previous header() call. So, when setting the Cache-Control, for example if one does not want to put all the arguments in one header() function call, he must do something like this:

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

See more complete documentation here.

Apprehension answered 18/9, 2008 at 10:36 Comment(4)
This is full of myths. pre-check and post-check are IE-only, relevant only for cached responses, and 0 value is a no-op. max-stale is proxy request header, not server response header. Expires accepts only single value. More than one will cause this header to be ignored.Kentiga
@porneL, will you be submitting a competing answer that deals with these myths correctly?Pacian
@Oddthinking, looks like stackoverflow.com/questions/49547/… is a competing answer.Pallas
@Outhouse yes, as I say in the disclaimer, use BalusC's answer.Apprehension
U
8

These directives does not mitigate any security risk. They are really intended to force UA's to refresh volatile information, not keep UA's from being retaining information. See this similar question. At the very least, there is no guarantee that any routers, proxies, etc. will not ignore the caching directives as well.

On a more positive note, policies regarding physical access to computers, software installation, and the like will put you miles ahead of most firms in terms of security. If the consumers of this information are members of the public, the only thing you can really do is help them understand that once the information hits their machine, that machine is their responsibility, not yours.

Upraise answered 19/9, 2008 at 3:8 Comment(0)
S
7

Setting the modified http header to some date in 1995 usually does the trick.

Here's an example:

Expires: Wed, 15 Nov 1995 04:58:08 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Cache-Control: no-cache, must-revalidate
Samiel answered 8/9, 2008 at 12:10 Comment(1)
Setting a long-ago Last-Modified has no impact on caching, other than letting a cached response be used longer due to heuristic revalidation.Bandaranaike
C
7

The RFC for HTTP 1.1 says the proper method is to add an HTTP Header for:

Cache-Control: no-cache

Older browsers may ignore this if they are not properly compliant to HTTP 1.1. For those you can try the header:

Pragma: no-cache

This is also supposed to work for HTTP 1.1 browsers.

Coeternal answered 8/9, 2008 at 12:14 Comment(1)
The spec indicates that the response must not be reused without revalidation. It is the Cache-Control:no-store which is the official method to indicate that the response not even be stored in a cache in the first place.Ney
B
7

If you're facing download problems with IE6-IE8 over SSL and cache:no-cache header (and similar values) with MS Office files you can use cache:private,no-store header and return file on POST request. It works.

Benjamin answered 21/9, 2012 at 9:2 Comment(0)
V
6

The PHP documentation for the header function has a rather complete example (contributed by a third party):

    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);
Volscian answered 8/9, 2008 at 12:19 Comment(4)
This is obviously wrong. Second calls to header() for Expires, Cache-control and Pragma completely overwrite previously set values.Kentiga
@porneL: No the do not overwrite previously set values as he pass false as a 2nd parameter, telling to not override previous values.Mercantile
@JulienPalard the answer has been edited after I made my comment. It still doesn't make much sense.Kentiga
Do not send multiple Cache-Control headers if you want to work in IE prior to 9. Don't EVER send pre-check or post-check. blogs.msdn.com/b/ieinternals/archive/2009/07/20/…Bandaranaike
H
5

in my case i fix the problem in chrome with this

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

where i need to clear the content of a previus form data when the users click button back for security reasons

Hypoblast answered 19/6, 2013 at 17:28 Comment(1)
My mozilla 19.x browser issue also got resolved by the code snippet. autocomplete="off". Thank you.Cadenza
D
5

The accepted answer does not appear to work for IIS7+, going by the large number of questions about cache headers not being sent in II7:

And so on

The accepted answer is correct in which headers must be set, but not in how they must be set. This way works with IIS7:

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

The first line sets Cache-control to no-cache, and the second line adds the other attributes no-store, must-revalidate

Domingodominguez answered 18/3, 2014 at 0:45 Comment(1)
This works for me: Response.Cache.SetAllowResponseInBrowserHistory(false); Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetNoStore(); Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);Chafin
C
4

I've had best and most consistent results across all browsers by setting Pragma: no-cache

Cushiony answered 17/9, 2008 at 12:32 Comment(0)
C
4

In addition to the headers consider serving your page via https. Many browsers will not cache https by default.

Corin answered 19/11, 2008 at 8:31 Comment(0)
N
4

The headers in the answer provided by BalusC does not prevent Safari 5 (and possibly older versions as well) from displaying content from the browser cache when using the browser's back button. A way to prevent this is to add an empty onunload event handler attribute to the body tag:

<body onunload=""> 

This hack apparently breaks the back-forward cache in Safari: Is there a cross-browser onload event when clicking the back button?

Nickeliferous answered 23/4, 2011 at 21:24 Comment(1)
Cool, I've tested it and this actually works on Safari (5.1.7) but not Opera.Outhouse
S
4

Also, just for good measure, make sure you reset the ExpiresDefault in your .htaccess file if you're using that to enable caching.

ExpiresDefault "access plus 0 seconds"

Afterwards, you can use ExpiresByType to set specific values for the files you want to cache:

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

This may also come in handy if your dynamic files e.g. php, etc. are being cached by the browser, and you can't figure out why. Check ExpiresDefault.

Schiffman answered 19/8, 2016 at 20:47 Comment(0)
A
3
//In .net MVC
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult FareListInfo(long id)
{
}

// In .net webform
<%@ OutputCache NoStore="true" Duration="0" VaryByParam="*" %>
Allard answered 6/2, 2013 at 8:52 Comment(0)
A
1

To complete BalusC -> ANSWER If you are using perl you can use CGI to add HTTP headers.

Using 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 
                                           ))
        );
    }

Using 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>

Note: When I tried to use the html META, browsers ignored them and cached the page.

Affidavit answered 13/2, 2014 at 12:12 Comment(2)
I don't know what will be the behavior of the Apache with this config : - Pragma/Cache-Control has the same role and you give them 2 differents configs. It's weird. - no-store mean that the ressource should not be cached. So how can it be revalidated ?Tocsin
Error 500 due to FilesMatch was not closedPetrolatum
C
0

I just want to point out that if someone wants to prevent caching ONLY dynamic content, adding those additional headers should be made programmatically.

I edited configuration file of my project to append no-cache headers, but that also disabled caching static content, which isn't usually desirable. Modifying response headers in code assures that images and style files will be cached.

This is quite obvious, yet still worth mentioning.

And another caution. Be careful using ClearHeaders method from HttpResponse class. It may give you some bruises if you use it recklessly. Like it gave me.

After redirecting on ActionFilterAttribute event the consequences of clearing all headers are losing all session data and data in TempData storage. It's safer to redirect from an Action or don't clear headers when redirection is taking place.

On second thought I discourage all to use ClearHeaders method. It's better to remove headers separately. And to set Cache-Control header properly I'm using this code:

filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Codger answered 20/5, 2014 at 12:35 Comment(0)
W
0

See this link to a Case Study on Caching:

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

Summary, according to the article, only Cache-Control: no-store works on Chrome, Firefox and IE. IE accepts other controls, but Chrome and Firefox do not. The link is a good read complete with the history of caching and documenting proof of concept.

Wycoff answered 3/7, 2014 at 14:51 Comment(0)
A
0

I had no luck with <head><meta> elements. Adding HTTP cache related parameters directly (outside of the HTML doc) does indeed work for me.

Sample code in Python using web.py web.header calls follows. I purposefully redacted my personal irrelevant utility code.


    import web
    import sys
    import PERSONAL-UTILITIES

    myname = "main.py"

    urls = (
        '/', 'main_class'
    )

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

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

    class main_class(object):
        def GET(self):
            web.header("Cache-control","no-cache, no-store, must-revalidate")
            web.header("Pragma", "no-cache")
            web.header("Expires", "0")
            return 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("Expires", "0")
            return render.index_laid_out(greeting = msg + form.function)

    if __name__ == "__main__":
        nargs = len(sys.argv)
        # Ensure that there are enough arguments after python program name
        if nargs != 2:
            LOG-AND-DIE("%s: Command line error, nargs=%s, should be 2", myname, nargs)
        # Make sure that the TCP port number is numeric
        try:
            tcp_port = int(sys.argv[1])
        except Exception as e:
            LOG-AND-DIE ("%s: tcp_port = int(%s) failed (not an integer)", myname, sys.argv[1])
        # All is well!
        JUST-LOG("%s: Running on port %d", myname, tcp_port)
        web.httpserver.runsimple(main.wsgifunc(), ("localhost", tcp_port))
        main.run()

Alexis answered 10/8, 2016 at 22:11 Comment(2)
Is this not covered many times already in the answers that have been on the site for years?Twomey
META directives work in Internet Explorer and versions of Edge 18 and earlier. Modern browsers do not support them. crbug.com/2763Bandaranaike
S
0

i have solved in this way.

2 considerations:

1) the server side events are not fired on back click, instead of javascript.

2) i have 2 javascript to read/write cookies

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;
}

in my Page_Load i inserted this: (this is NOT fired on back click)

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

where 'Login' is my id value that is -1 after logout (you could use something else, a boolean for example).

then in my page i added this: (this IS fired on back click)

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

</script>

nothing else.

with this solution back click is enable on every page and disable only after logout on each page on the same browser.

Severalty answered 12/6, 2020 at 8:51 Comment(0)
K
0

For IIS web.config you can use this:

<configuration>
  <system.webServer>
    <rewrite>
      <outboundRules>
        <rule name="RewriteCacheControlForHtmlFile" preCondition="IsHtmlFile">
          <match serverVariable="RESPONSE_Cache_Control" pattern=".*" />
          <action type="Rewrite" value="no-cache, no-store, must-revalidate" />
        </rule>
        <rule name="RewritePragmaForHtmlFile" preCondition="IsHtmlFile">
          <match serverVariable="RESPONSE_Pragma" pattern=".*" />
          <action type="Rewrite" value="no-cache" />
        </rule>
        <rule name="RewriteExpiresForHtmlFile" preCondition="IsHtmlFile">
          <match serverVariable="RESPONSE_Expires" pattern=".*" />
          <action type="Rewrite" value="0" />
        </rule>
        <preConditions>
          <preCondition name="IsHtmlFile">
            <add input="{RESPONSE_CONTENT_TYPE}" pattern="html$" />
          </preCondition>
        </preConditions>
      </outboundRules>
    </rewrite>
    <security>
      <requestFiltering allowDoubleEscaping="true" />
    </security>
  </system.webServer>
</configuration>

It will only apply to the index files and not other files you still might want to be cached.

Kielty answered 10/1 at 13:0 Comment(0)
P
-1

you can use location block for set individual file instead of whole app get caching in IIS

 <location path="index.html">
    <system.webServer>
      <httpProtocol>
        <customHeaders>
          <add name="Cache-Control" value="no-cache" />
        </customHeaders>
      </httpProtocol>
    </system.webServer>
  </location>
Peracid answered 12/5, 2020 at 5:30 Comment(0)
L
-3

Not sure if my answer sounds simple and stupid, and perhaps it has already been known to you since long time ago, but since preventing someone from using browser back button to view your historical pages is one of your goals, you can use:

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

Of course, this may not be possible to be implemented across the entire site, but at least for some critical pages, you can do that. Hope this helps.

Lexi answered 29/5, 2020 at 12:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.