I just now found this question, and after puzzling over Chrome's If_Modified_Since
behavior, I've found the answer.
Chrome's decision to cache files is based on the Expires
header that it receives. The Expires
header has two main requirements:
- It must be in Greenwich Mean Time (GMT), and
- It must be formatted according to RFC 1123 (which is basically RFC 822 with a four-digit year).
The format is as follows:
Expires: Sat, 07 Sep 2013 05:21:03 GMT
For example, in PHP, the following outputs a properly formatted header.
$duration = time() + 3600 // Expires in one hour.
header("Expires: " . gmdate("D, d M Y H:i:s", $duration) . " GMT");
("GMT" is appended to the string instead of the "e" timezone flag because, when used with gmdate()
, the flag will output "UTC," which RFC 1123 considers invalid. Also note that the PHP constants DateTime::RFC1123
and DATE_RFC1123
will not provide the proper formatting, since they output the difference to GMT in hours [i.e. +02:00] rather than "GMT".)
See the W3C's date/time format specifications for more info.
In short, Chrome will only recognize the header if it follows this exact format. This, combined with the Cache-Control
header...
header("Cache-Control: private, must-revalidate, max-age=" . $duration);
...allowed me to implement proper cache control. Once Chrome recognized those headers, it began caching the pages I sent it (even with query strings!), and it also began sending the If_Modified_Since
header. I compared it to a stored "last-modified" date, sent back HTTP/1.1 304 Not Modified
, and everything worked perfectly.
Hope this helps anyone else who stumbles along!