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 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:
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.
Warning! This answer is too old and doesn't work on modern browsers.
I'm not the poster of this answer, but at the time of writing this, this is the most voted answer by far in both positive and negative votes (+1035 -17), and it's still marked as accepted answer (probably because the original poster of the question is the one who wrote this answer).
As already noted many times in the comments, this answer does not work on most browsers anymore (and seems to be failing to do that since 2013).
After over an hour of tweaking, testing, and trying different styles of markup, I think I may have a decent solution. The requirements for this particular project were:
- Inputs must be on their own line.
- Checkbox inputs need to align vertically with the label text similarly (if not identically) across all browsers.
- If the label text wraps, it needs to be indented (so no wrapping down underneath the checkbox).
Before I get into any explanation, I'll just give you the code:
label {
display: block;
padding-left: 15px;
text-indent: -15px;
}
input {
width: 13px;
height: 13px;
padding: 0;
margin:0;
vertical-align: bottom;
position: relative;
top: -1px;
*overflow: hidden;
}
<form>
<div>
<label><input type="checkbox" /> Label text</label>
</div>
</form>
Here is the working example in JSFiddle.
This code assumes that you're using a reset like Eric Meyer's that doesn't override form input margins and padding (hence putting margin and padding resets in the input CSS). Obviously in a live environment you'll probably be nesting/overriding stuff to support other input elements, but I wanted to keep things simple.
Things to note:
- The
*overflow
declaration is an inline IE hack (the star-property hack). Both IE 6 and 7 will notice it, but Safari and Firefox will properly ignore it. I think it might be valid CSS, but you're still better off with conditional comments; just used it for simplicity.
- As best I can tell, the only
vertical-align
statement that was consistent across browsers was vertical-align: bottom
. Setting this and then relatively positioning upwards behaved almost identically in Safari, Firefox and IE with only a pixel or two of discrepancy.
- The major problem in working with alignment is that IE sticks a bunch of mysterious space around input elements. It isn't padding or margin, and it's damned persistent. Setting a width and height on the checkbox and then
overflow: hidden
for some reason cuts off the extra space and allows IE's positioning to act very similarly to Safari and Firefox.
- Depending on your text sizing, you'll no doubt need to adjust the relative positioning, width, height, and so forth to get things looking right.
Hope this helps someone else! I haven't tried this specific technique on any projects other than the one I was working on this morning, so definitely pipe up if you find something that works more consistently.
Warning! This answer is too old and doesn't work on modern browsers.
Best Answer
[UPDATE]
The original question, and the answer below applied specifically to the IE11 preview releases.
The final release version of IE11 does in fact provide the ability to switch browser modes from the Emulation tab in the dev tools:
Having said that, the advice I've given here (and elsewhere) to avoid using compatibility modes for testing is still valid: If you want to test your site for compatibility with older IE versions, you should always do your testing in a real copy of those IE version.
However, this does mean that the registry hack described in @EugeneXa's answer to bring back the old dev tools is no longer necessary, since the new dev tools do now have the feature he was missing.
[ORIGINAL ANSWER]
The IE devs have deliberately deprecated the ability to switch browser mode.
There are not many reasons why people would be switching modes in the dev tools, but one of the main reasons is because they want to test their site in old IE versions. Unfortunately, the various compatibility modes that IE supplies have never really been fully compatible with old versions of IE, and testing using compat mode is simply not a good enough substitute for testing in real copies of IE8, IE9, etc.
The IE devs have recognised this and are deliberately making it harder for devs to make this mistake.
The best practice is to use real copies of each IE version to test your site instead.
The various compatiblity modes are still available inside IE11, but can only be accessed if a site explicitly states that it wants to run in compat mode. You would do this by including an
X-UA-Compatible
header on your page.And the Document Mode drop-box is still available, but will only ever offer the options of "Edge" (that is, the best mode available to the current IE version, so IE11 mode in IE11) or the mode that the page is running in.
So if you go to a page that is loaded in compat mode, you will have the option to switch between the specific compat mode that the page was loaded in or IE11 "Edge" mode.
And if you go to a page that loads in IE11 mode, then you will only be offered the 'edge' mode and nothing else.
This means that it does still allow you to test how a compat mode page reacts to being updated to work in Edge mode, which is about the only really legitimate use-case for the document mode drop-box anyway.
The IE11 Document Mode drop box has an
i
icon next to it which takes you to the modern.ie website. The point of this is to encourage you to download the VMs that MS are supplying for us to test our sites using real copies of each version of IE. This will give you a much more accurate testing experience, and is strongly enouraged as a much better practice than testing by switching the mode in dev tools.Hope that explains things a bit for you.