This tutorial will show you the vital role cache validators play in requests. It will also show you how to use the Last-Modified or ETag header to enable cache validation for various resources.

What Cache Validators Look Like in Action

Cache validators are request and response headers that indicate the validity of a requested file against a local browser cache. When a browser opens a file for the first time, it stores it in it’s local cache based on various cache validators. This way subsequent requests don’t have to be loaded from the server, thus saving bandwidth.

So what does a request like this look like?

Looking into Firefox browser and how it sends request (using Inspect Element), you can see that request headers are the most important part of the request:

First Request

Request headers and cache validators in first request.

This request corresponds with following CURL line:

~$ curl

This will get a response from the server with status code 200 showing that the requested file was delivered:

Response headers and cache validators in first response.

Second Request

At this point, the file we requested is cached in the browser’s local cache. Now when the next request comes in (reload page), the browser will be aware of a previously cached file. And for optimization purposes, it will include the “Last-Modified” header value in a request. This header value will ask if the file was changed since the last time it was requested.

The request corresponds with the following CURL line:

~$ curl -H ‘If-Modified-Since: Wed, 09 Oct 2013 01:35:39 GMT’

The request headers from the browser look like the following:

Request headers and cache validators in second request.

This request is literarily asking server “Hey, did this file get changed since this time: ‘Wed, 09 Oct 2013 01:35:39 GMT’?”

If the file is unchanged, the browser will get a response of status code 304. In english, this translates to: “Nope, this file didn’t get change since that time, load it from your local cache”.

The response headers look like so:

Response headers and cache validators in second response.

Last-Modified is one header that is providing cache validation; however, there is another one equally important called ETag (Entity Tag). The purpose of this this header is the same and it’s value is used to determine validity of a requested file.

The ETag contains a value that identifies it’s content and it and changes accordingly if content is changed. The algorithm used to generate ETags is a collision-resistant hash function generated on the base of a file content.

A request with Etag corresponds with the following CURL example:

~$ curl -H ‘If-None-Match: 123456789’

The resulting response header from the server should be 304 if the file’s ETag value on the server matches the ETag the browser contains.


How to Specify Cache Validation Headers

Web servers add the Last-Modified header to your assets automatically. However you can add it yourself on a dynamic file in which case you’d need to code the header within the dynamic file itself:

@header ('Last-Modified: ' . gmstrftime("%a, %d %b %Y %H:%M:%S GMT", time() - 20)); //60*60*3

[View gmstrftime documentation]

As for ETag headers, assuming apache is the web server you are serving assets from, ETag would not be necessary as the validation is already handled by Last-Modified.

Setting ETag directive consists of:

  • INode – the file system object identificator
  • MTime – the time the file was last modified
  • Size – represents file size in bytes

The Apache configuration directive looks like this:

<directory usr="" local="" httpd="" htdocs="">
    FileETag INode MTime Size

And here is an example ETag header:

ETag: "26664aa-5f1-80d90aa4"

With 10690a1 equaling INode, 5f1 equaling MTime, and 80d90aa4 equaling Size.


How to Direct Cache Validation Issues

If you get a cache validation suggestion from a performance testing tool like Pingdom, it probably means you have some external 3rd party resources being loaded from buckets where Last-Modified and/or ETag headers are stripped off intentionally.

If the location is not under your control, ignore this suggestion as access control limits are in place.

What If Last-Modified Isn’t In Response Headers List?

Depending on who managed your server, it is possible that this header was removed due to false conviction of Last-Modified being bad for performance. If this is the case, you should see “unset” directive with following format:

Header unset Last-Modified

This should be removed (from htaccess or config file). If needed, you should also restart server to apply config reset (restart is needed if you are changing config file only – not htaccess).

To confirm header is set ,running CURL as follows should produce response headers as described:

~$ curl -I
HTTP/1.1 200 OK
Date: Thu, 15 Jan 2015 02:48:46 GMT
Content-Type: image/png
Content-Length: 51851
Connection: keep-alive
Last-Modified: Wed, 14 Jan 2015 23:53:03 GMT
Server: NetDNA-cache/2.2
Expires: Thu, 22 Jan 2015 02:48:46 GMT
Cache-Control: max-age=604800
X-Cache: HIT
Accept-Ranges: bytes