What takes precedence: the ETag or Last-Modified HTTP header?

For two subsequent requests, which of the following two headers is given more weight by browsers should one of them change: ETag or Last-Modified?


According to RFC 2616 section 13.3.4, an HTTP 1.1 Client MUST use the ETag in any cache-conditional requests, and if both an ETag and Last Modified are present, it SHOULD use both. The ETag header is considered a strong validator (see section 13.3.3), unless explicitly declared weak by the server, whereas the Last Modified header is considered weak unless at least a minute difference exists between it and the Date header. Note, however that the Server is not required to send either (but it SHOULD, if it can).

Note that the Client does not check the headers to see if they have changed; it just blindly uses them in the next conditional request; it is up to the Server to evaluate whether to send the requested content or a 304 Not Modified response. If the Server only sends one, then the Client will use that one alone (although, only strong validators are useful for a Range request). Of course, it is also at the discretion of intermediate caches (unless they have been prevented from caching via Cache Control directives) and the Server as to how they will act upon the headers; the RFC states that they MUST NOT return a 304 Not Modified if the validators are inconsisent, but since the header values are generated by the server, it has quite a bit of leeway.

In practice, I have noticed that Chrome, FireFox, and IE 7+ all send both headers, if available. I also tested the behavior when sending modified headers, which I had already suspected from the information in the RFC. The four clients I tested only sent conditional requests if the page(s) were refreshed or if it was the first time the page had been requested by the current process.


Isn't it more like an "OR" expression. In pseudo code:

if ETagFromServer != ETagOnClient || LastModifiedFromServer != LastModifiedOnClient
   GetFromServer
else
   GetFromCache

=! is the correct comparison operator. The client is required to keep the literal string received from the server, as conversions can create small differences. You can not assume that 'newer is better'.

Why? Consider the case where the server operator reverts a bad version of a resource. The reverted version is OLDER - but correct.

The client must use the version currently offered by the server; it can use a cached version only if it is the same. Thus the server must check equality, not 'newer'.