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 cached, ever, by the web browser. This must work for at least the following browsers:
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
Cache-Control is per the HTTP 1.1 spec for clients and proxies (and implicitly required by some clients next to
Pragma is per the HTTP 1.0 spec for prehistoric clients. The
Expires is per the HTTP 1.0 and 1.1 spec 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.
Pragma could be omitted if you don't care about HTTP 1.0 clients (HTTP 1.1 was introduced 1997). If the server auto-includes a valid
Date header, then you could theoretically omit
Cache-Control too and rely on
Expires only, but that may fail if e.g. the enduser manipulates the operating system date and the client software is relying on it.
Cache-Control parameters such as
max-age are irrelevant if the abovementioned three 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.
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.
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.
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.
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 on Flask:
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 Google 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.
<IfModule mod_headers.c> Header set Cache-Control "no-cache, no-store, must-revalidate" Header set Pragma "no-cache" Header set Expires 0 </IfModule>
<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" />
Important to know is that when a HTML page is served over a 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 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.
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:
First of all, this question and answer is 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.