Last month we talked about various caching layers last month. The latest 'line of defense' is conditional caching.
What is Conditional Caching?
Browser usually has a lot of resources in its local cache. Some of them can be expired but browser can check if they can be used once more. So there is a way (frankly speaking two different ways) to check if a resource can be used once more.
First we can use
Last-Modified (specified in HTTP/1.0) and its pair —
If-Modified-Since. Server sends header
Last-Modified with the resource modification date. Browser can request if resource was changed since the last request and send this date back with
If-Modified-Since header. If there were no modifications server responses with 304-answer.
There is almost the same situation with
If-Match) headers. Expect the only thing that Entity Tag can be any string (date, set of numbers, file name, etc). So this allows you to define it any way. But
ETag belongs to HTTP/1.1 specification.
With 304-answers server actually doesn't send any content to browser so you save transfer time for these resources.
If can be also useful for a kind of dynamic content which can't be cached for a long time but can't be changed often. So browser re-requests such content (if cache is expired) but receives answer 'Not modified'.
Also if helps with pages' reload - when visitor presses
Ctrl+R in his/her browser the latter must request from the server all resources. So such kind of refresh can be made faster with conditional caching.
Apache server usually sends
Last-Modified. There is
mod_headers that is responsible for such behavior (and it seems for 304-answers). You can add
ETag header (which indicates file modification time only) this way:
You can also unset each of these headers:
Header unset Last-Modified
Header unset ETag
With PHP you can send the equivalent of these headers by:
header("Last-Modified: " . gmdate("D, d M Y H:i:s", $time));
header("ETag: \"" . md5(gmdate("D, d M Y H:i:s", $time)) . "\"");
If you want to emulate 'classic' ETag which Apache server sends by default you need to use:
header("ETag: \"" . dec2hex(@fileinode($filename)) . '-' .
dec2hex(@filesize($filename)) . '-' . dec2hex($mtime) . "\"");
dec2hec is a helper to convert numbers for correct conversion numbers from decimal to heximal.
First of all you need to send different conditional headers with compressed and not compressed content. Generic approach here is to add '-gzip' to the end of the
ETag (there is nothing to do with
Last-Modified so it's a bit less usable).
Then you need to make such headers equal through all servers you use to server content. Because common ETag header in Apache includes information about inode (server-related, but not actually file-related), so it must be eliminated or replaced.
Then there is information (not approved yet) about excessive requests from browsers with conditional headers. Please be careful with this.
For static resources Web Optimizer unsets
Last-Modified header for all static resources and sets
ETag based on modification time. For dynamic ones it (if HTML documents are cached) sets ETag based on content hash and Last-Modified with static PHP proxy.