By Edward Wilde


2008-09-08 12:08:49 8 Comments

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.

26 comments

@BalusC 2010-01-14 23:50:18

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

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, or 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.

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 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 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 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 other, you can see/debug them in HTTP traffic monitor of webbrowser'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 URI path or querystring 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.

@Mike Ottum 2010-01-15 02:26:46

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.

@BalusC 2010-01-15 03:38:18

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

@vkGunasekaran 2012-04-20 06:45:56

@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.net

@Curtis 2012-05-30 20:33:23

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 pages

@haylem 2012-10-02 22:46:51

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.

@Keith 2012-10-29 11:51:41

@haylem IE6, 7 and 8 must have no-store before no-cache and can't have a Pragma header on HTTPS connections.

@John 2013-02-12 16:14:25

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.

@BalusC 2013-02-12 16:18:18

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

@John 2013-02-12 16:27:48

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

@Luka Ramishvili 2013-02-16 10:37:40

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_docs

@BalusC 2013-02-16 11:33:48

@Luka: as stated in the answer: "The HTML meta tag will only be used when the page is viewed from local disk file system."

@Luka Ramishvili 2013-02-21 11:00:37

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

@coredumperror 2013-03-22 18:26:14

@haylem 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.

@BalusC 2013-03-22 18:31:15

@CoreDumpError: note that haylem's comment concerns downloading files via IE8 which is answered here. This is further unrelated to "this solution".

@Raman Ghai 2013-05-11 13:27:34

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() ?

@BalusC 2013-05-12 02:50:24

@Raman: Do not repeat code nor write Java code in JSP. Use a filter.

@Pacerier 2013-08-25 19:06:34

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

@BalusC 2013-08-25 19:08:19

@Pacerier: you're right, but browsers not. The intent is to cover all browsers, also those who are wrong.

@Pacerier 2013-08-25 19:20:34

@BalusC, so are you suggesting we do some rojak like stackoverflow.com/a/49549/632951 ?

@Pacerier 2013-08-29 04:32:26

@BalusC, your solution doesn't work on Safari 5.1.7 and Opera

@Robert Christ 2014-01-13 23:48:42

@Keith this is wrong, IE 8 can accept Pragma over HTTPS, but just not no-cache stackoverflow.com/questions/3415370/…

@Keith 2014-01-14 16:30:08

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

@symcbean 2014-02-14 16:31:03

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

@Darrel Miller 2014-02-20 23:11:07

@symcbean 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.

@Chameera Dedduwage 2014-06-03 09:26:32

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

@BalusC 2014-06-03 10:06:04

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

@Chameera Dedduwage 2014-06-09 06:01:42

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

@BalusC 2014-06-09 06:03:13

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

@Hello World 2014-08-29 12:25:14

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

@Luke Hutchison 2014-12-30 14:07:06

Shouldn't "Expires" be a date (the same value as the "Date" header), not the number "0"? See mnot.net/cache_docs

@BalusC 2014-12-30 14:16:19

@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").".

@Uri 2015-03-08 12:39:12

I can't define Pragma: no-cache on Amazon S3, do you know why? Does it work without Pragma: no-cache too?

@ivo Welch 2015-09-03 15:03:45

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

@BalusC 2015-09-03 19:34:39

@ivoWelch: it's indeed not allowed anymore in HTML5. Just use response headers as recommended in answer.

@sivann 2016-03-13 10:27:29

Isn't pragma a request header?

@BalusC 2016-06-05 12:22:01

@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).

@ilovetolearn 2016-09-13 06:58:33

@BalusC are the HTTP headers required on every page or just the index page?

@a cat 2016-09-16 16:14:32

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.

@Alvaro Montoro 2017-01-25 16:12:28

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?

@venugopal 2017-09-08 05:39:14

This helped me in making Jquery Ajax call without adding time stamp to the get url

@GettnDer 2017-11-15 19:21:51

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 reload

@BalusC 2017-11-15 20:50:42

@GettnDer 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.

@GettnDer 2017-11-15 22:31:38

That's what I figured, but wanted to make sure. Specially since I'll probably deal with it on a global-filter basis

@Hussain 2018-02-05 02:34:21

Could someone tell me how to fix this in Django? Everything I tried doesn't work for Safari

@Dov Miller 2019-06-12 10:36:44

In ASP.NET would code be put in Page_Load or Page_Init?

@JD Smith 2019-08-26 18:30:03

The following post was helpful to me - I've used a combination of this answer and that one: stackoverflow.com/questions/24604921/…

@Paul 2014-07-03 14:51:34

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.

@Joseph Connolly 2012-06-15 02:40:53

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

@Ibrahim ben Salah 2015-04-12 09:56:22

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>

@another 2016-12-13 12:46:47

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

@Obinwanne Hill 2016-08-19 20:47:34

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.

@Richard Elkins 2016-08-10 22:11:11

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

@Martin Tournoij 2016-08-10 22:33:53

Is this not covered many times already in the answers that have been on the site for years?

@Kornel 2011-03-30 23:08:03

(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 IE-only directive that only applies to cachable resources.
  • Sending same header twice or in dozen parts. Some PHP snippets out there actually replace previous headers, resulting in only 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.

@Raman Ghai 2013-05-22 14:43:57

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 ?

@Kornel 2013-05-22 16:01:44

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

@Pacerier 2013-08-25 19:15:28

@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.1

@Kornel 2013-08-27 17:29:49

@Pacerier 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.

@Pacerier 2013-08-29 03:35:59

@porneL, Hmm is there a supporting RFC that states that's the desired behavior?

@Pacerier 2014-06-22 12:58:52

@porneL, I've just tested your solution (https + must-revalidate). It works on Opera but not Chrome, IE, Safari, FireFox....

@kspearrin 2016-05-19 19:55:19

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

then register it with Startup.cs

app.UseMiddleware<NoCacheMiddleware>();

Make sure you add this somewhere after

app.UseStaticFiles();

@Victor Sharovatov 2018-06-07 08:16:30

I would suggest to use constants from Microsoft.Net.Http.Headers.HeaderNames instead of string literals "Cache-Controls", "Pragma" and "Expires".

@user3253726 2014-05-20 12:35:10

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

@JK. 2014-03-18 00:45:57

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

@Vilx- 2015-04-29 12:02:50

This works for me: Response.Cache.SetAllowResponseInBrowserHistory(false); Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetNoStore(); Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCach‌​es);

@Carlos Escalera Alonso 2014-02-13 12:12:40

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.

@Pacerier 2013-08-29 16:50:36

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

@Jordan 2015-07-15 22:22:34

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.

@Pacerier 2015-11-26 04:52:14

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

@Edson Medina 2013-06-13 15:23:52

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

@user2321638 2013-06-19 17:28:58

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

@Satya 2013-11-22 07:33:46

My mozilla 19.x browser issue also got resolved by the code snippet. autocomplete="off". Thank you.

@yongfa365 2013-02-06 08:52:53

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

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

@Albert 2012-09-21 09:02:33

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.

@Grey Panther 2008-09-08 12:19:23

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

@Kornel 2008-10-19 18:22:41

This is obviously wrong. Second calls to header() for Expires, Cache-control and Pragma completely overwrite previously set values.

@Julien Palard 2013-02-14 10:52:59

@porneL: No the do not overwrite previously set values as he pass false as a 2nd parameter, telling to not override previous values.

@Kornel 2013-02-15 10:31:21

@JulienPalard the answer has been edited after I made my comment. It still doesn't make much sense.

@EricLaw 2015-04-14 12:51:34

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

@Tobias 2011-04-23 21:24:11

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?

@Pacerier 2013-08-29 04:59:50

Cool, I've tested it and this actually works on Safari (5.1.7) but not Opera.

@Chris Vasselli 2010-01-14 23:35:52

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.

@coredumperror 2013-03-22 21:38:59

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.

@coredumperror 2013-03-22 21:46:04

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.

@Pacerier 2013-08-25 19:55:40

@CoreDumpError, oh you should not assume JavaScript is enabled.

@Chris Vasselli 2013-08-31 00:45:54

@Pacerier 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.

@Pacerier 2013-10-02 12:35:31

What were the browser versions you tested with?

@Chris Vasselli 2013-10-03 05:21:33

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.

@Steven Oxley 2008-09-18 10:36:40

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.

@Kornel 2008-10-19 18:19:50

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.

@Oddthinking 2008-11-28 01:56:23

@porneL, will you be submitting a competing answer that deals with these myths correctly?

@Mike Ottum 2010-01-14 23:55:20

@Oddthinking, looks like stackoverflow.com/questions/49547/… is a competing answer.

@Steven Oxley 2013-09-04 16:17:57

@Pacerier yes, as I say in the disclaimer, use BalusC's answer.

@Harry 2008-11-19 08:31:33

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

@Anders Sandvig 2008-09-08 12:10:33

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

@EricLaw 2015-04-14 12:52:52

Setting a long-ago Last-Modified has no impact on caching, other than letting a cached response be used longer due to heuristic revalidation.

@Dustman 2008-09-19 03:08:52

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.

@Dave Cheney 2008-09-17 14:18:00

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

@michaelok 2012-07-10 18:42:13

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.

@EricLaw 2015-04-14 12:53:38

@michaelok: Your reference is valid, but misses the larger point-- Set a proper Cache-Control/Expires and you don't need pragma.

@petr k. 2008-09-17 12:32:53

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

@Edward Wilde 2008-09-08 12:11:57

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

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

@Cᴏʀʏ 2012-02-13 19:51:53

@bart: Even more troublesome yet is that the 26th of July in 1997 was a Saturday, not a Monday...

@Keith 2012-10-29 11:48:22

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.

@EricLaw 2015-04-14 12:54:18

Do not use pre-check and post-check. blogs.msdn.com/b/ieinternals/archive/2009/07/20/…

@Andy 2015-12-18 17:00:40

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

@Chris Dail 2008-09-08 12:14:57

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.

@AnthonyWJones 2008-09-19 18:14:06

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.

Related Questions

Sponsored Content

50 Answered Questions

[SOLVED] How to force the browser to reload cached CSS/JS files?

16 Answered Questions

[SOLVED] How to force a web browser NOT to cache images

9 Answered Questions

[SOLVED] What's the difference between Cache-Control: max-age=0 and no-cache?

15 Answered Questions

[SOLVED] How long do browsers cache HTTP 301s?

18 Answered Questions

6 Answered Questions

4 Answered Questions

[SOLVED] Difference between no-cache and must-revalidate

  • 2013-08-09 14:19:30
  • Luke Puplett
  • 121223 View
  • 167 Score
  • 4 Answer
  • Tags:   http

2 Answered Questions

[SOLVED] ISP caching certain browsers?

  • 2017-11-07 11:49:26
  • user3434591
  • 602 View
  • 0 Score
  • 2 Answer
  • Tags:   caching browser

0 Answered Questions

Firefox Browser fail to cache swf files

  • 2013-11-29 14:54:45
  • user3049746
  • 74 View
  • 1 Score
  • 0 Answer
  • Tags:   firefox caching

2 Answered Questions

Sponsored Content