Sunday, May 22, 2011

Caching Cufon Javascript Files via Apache HTTP Response Headers

In a comment on a previous post, someone wanted to know how to cache data returned by the server in order to save time from extra Cufon Javascript file loads. This can be done since we have access to headers like expires and cache control. In Cufon, the data that describes the font is placed in a Javascript file. This is the file you download when running the Cufon generator.

When using Cufon, one thing we do not want is for the browser to retrieve a fresh copy of that Javascript file each time the page loads or refreshes. After the Browser has downloaded the file once, we'd like to cache it to save the download time.

You can see here in Firebug that the Javascript files we are downloading with the Cufonized "MS Trebuchet" font does not have HTTP Expires or Cache Control headers.

But you can see here that font files downloaded from Google have both an Expires and Cache Control header.

We want to have the Expires and Cache-Control headers sent down with our Cufon-generated Javascript files. To do this, we can make a change to our Apache server configuration to tell it to send down these headers.

We simply need to put a .htaccess file on the server in the directory where the Cufon js file resides.

We can do that by either logging on to our server using SSH and creating the file with an editor on the server, or we can create the file on our local machine and transfer it to the server using Filezilla or other file transfer program.

The file must be called .htaccess, and will have these contents:

<Files *.js>
Header add "Cache-Control" "max-age=604800"
Header set Expires "Thu, 14 May 2015 20:00:00 GMT"

The max-age parameter of the Cache-Control header tells the Browser that the file can be cached until the given number of seconds elapses. The Expires header tells the Browser that the current file expires at a future time, after which the Browser should re-download a fresh copy instead of using the verion in cache.

By placing a .htaccess file in a directory on the server, you are telling Apache to apply some additional configuration settings just for the files in that directory. Since the .htaccess file as written will apply to all .js files in the directory, you want to make sure that it is OK to cache all of those files. If there is a .js file that you think should not be cached (e.g. because you are making frequent changes to it), then you should place that file in a separate directory that does not have the same .htaccess file settings.

With these changes applied, you can now see that the Expires and Cache-Control headers are being sent down for the "MS Trebuchet" font file.

A couple of other things to point out in the Response Headers are the "Last Modified" and "Etag" headers, as seen below. These are used in conjunction with the "If-Modified-Since" and "If-None-Match" request headers that the Browser sends to the Server. Basically the Browser remembers the last modified date from the "Last Modified" header, and the ETag value from the ETag header. It then sends those values back to the Server in the "If-Modified-Since" and "If-None-Match" headers, respectively. That allows Apache to then compare the values the Browser is sending up to the current version of the file residing on the server. Apache then makes a decision about whether the file should be sent down to the Browser, vs. telling to Browser to use the version in its cache.

So, just to re-iterate:

The If-Modified-Since request header asks the server if the file has changed since a certain date/time which is the date/time that the Browser received in the "Last Modifield" header. If the server sees that it has not been modified since then, it will send back a 304 Not Modified response, and the file content will not be sent down to the Browser.

The If-None-Match request header asks the server if the file's ETag value matches the ETag that was sent by the server when the Browser last downloaded the file. If the server sees that the ETag is unchanged, then it will send back a 304 Not Modified response, and the file content is not sent down to the Browser.

The ETag and "Last Modified" headers can be turned on/off via Apache configuration. My server already has them turned on, and I'll leave them that way. The one case where you would want to turn them off is if your site is hosted across multiple servers where the same file can come from one of many servers in a cluster, and where the file can have different attributes on the different servers in the cluster. In that case you are better off relying on just the Expires and Cache-Control headers.

As you can see there are multiple mechanisms in HTTP that can help the Browser to use files from its cache rather than re-downloading them, and each mechanism has its strengths and weaknesses.

Post a Comment