How to control web page caching, across all browsers?
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:
Our requirement came from a security test. After logging out from our website you could press the back button and view cached pages.
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 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.
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 eg the enduser 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:
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:
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 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.
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 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.
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:
I want to set those headers on file downloads too
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.
(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:
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. 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.
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:
Cache-Control: no-store
Cache-Control: no-cache
(https only)
Pragma: no-cache
(https only)
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:
Cache-Control: no-store
<body onunload="">
in html
Cache-Control: no-store
(https only)
In IE8 (v8.0.6001.18702IC) any one of these will work:
Cache-Control: must-revalidate, max-age=0
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: must-revalidate
Expires: 0
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
(https only)
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:
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
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
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
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
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
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
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
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
Cache-Control: no-store
Fail: Safari 5.1.7, Opera 12.15
Success: Chrome 28, FireFox 23, IE8
Cache-Control: no-store
<body onunload="">
Fail: Opera 12.15
Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: no-cache
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Vary: *
Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Success: none
Pragma: no-cache
Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Success: none
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
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
Cache-Control: must-revalidate, max-age=0
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Cache-Control: must-revalidate
Expires: 0
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
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
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:
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
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
Vary: *
Fail: Chrome 28, Safari 5.1.7, Opera 12.15
Success: FireFox 23, IE8
Pragma: no-cache
Fail: Chrome 28, Safari 5.1.7, Opera 12.15
Success: FireFox 23, IE8
Cache-Control: no-cache
Fail: Chrome 28, Safari 5.1.7, Opera 12.15
Success: FireFox 23, IE8
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
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
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
Cache-Control: must-revalidate
Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Success: Opera 12.15
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
Cache-Control: must-revalidate, max-age=0
Fail: Chrome 28, FireFox 23, Safari 5.1.7
Success: IE8, Opera 12.15
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Chrome 28, Safari 5.1.7
Success: FireFox 23, IE8, Opera 12.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, Safari 5.1.7
Success: FireFox 23, IE8, Opera 12.15
Cache-Control: no-store
Fail: Opera 12.15
Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7
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
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
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
Cache-Control: must-revalidate
Expires: 0
Fail: Chrome 28, FireFox 23, Safari 5.1.7,
Success: IE8, Opera 12.15
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
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
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
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
Cache-Control: no-store, must-revalidate
Fail: none
Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
上一篇: 如何强制浏览器重新加载缓存的CSS / JS文件?
下一篇: 如何在所有浏览器上控制网页缓存?