There are several things you can do to improve the performance and load times of your website. In this post, you will learn how to leverage browser caching by adding a few response headers for your static files.
While checking load speeds on sites like Pingdom, GTMetrix and Google PageSpeed, you might have seen warnings about the lack of caching. This guide helps to solve those warnings as well.
What does Browser Caching means?
As you know, a web page consists of not just HTML. It includes several static files like images, CSS, JS, etc.
So, when you go to a web page, your browser sends requests for all these files and downloads them.
The browsers come with the ability to store the downloaded responses on its cache on the local machine – that’s your device.
So, when you visit that page again after a while, the browser doesn’t require downloading all these files again. Instead, it retrieves these from the cache and renders the page.
This has several advantages:
- Avoids unwanted HTTP requests, resulting in faster page loads
- Saves your internet data charges
- Saves bandwidth for the website owner
However, the browser may not cache things by default. For that, the server has to inform the browser how long it should cache the files and when to validate it for changes. This is known as cache policy.
In short, cache policy consists of:
- Setting validity duration
- Cache re-validation method
The server informs its cache policy in the form HTTP response headers send with each file.
Important HTTP Headers for Caching
There are mainly four such headers that you should know about:
- ETag or Entity Tag
Each one is different and you can set one or more of these headers to define your cache policy.
Cache-control & Expires Header
Both these headers do almost the same thing albeit in a different way. They set the expiration time (validity) for a cached file.
Out of the two, Cache-control is newer. It allows setting multiple directives using less code.
Usually, adding the following code to the htaccess file is what you need in most cases to set caching.
Header Set Cache-Control "max-age=2592000, public"
Instead of explicitly setting the cache expiration for all files, you can <filesMatch> to match certain file types only:
This tells the browser to cache the files for the specified number of seconds. After that time, the browser has to request the server again.
You can adjust the time values based on the applications’s needs. Usually, for assets that rarely change, a value of one year will suffice.
The word public denotes that any client can cache the responses.
You can also do the opposite – that is, disable caching. The following will ask browsers to fetch fresh content from the server without caching.
Header Set Cache-Control "no-cache, no-store, must-revalidate"
Unlike Cache-control which sets a duration for the validity of cached files, Expires header sets a specific timestamp.
[The above code is based on the rules set by Breeze – a WordPress cache plugin]
Which one to use?
In most cases, Cache-control is enough to set proper policies. In today’s age, there are not many reasons to use the older Expires header. However, you can set both to ensure maximum support.
Validators: Last-modified & ETag Headers
Apache by default sends both ETag and Last-modified headers with the response. So, unless you turn these off, you should not see any warning during performance tests.
If GTMetrix’s PageSpeed recommends specifying a cache validator, it means you have to set either the Last-modified header or the ETag header or both.
Both do the same job – specifies when to validate the cache and refresh stale content.
Like Expires, Last-modified also specifies a time. For subsequent requests after the first one or after the cached content expires, the browser sends the date along with the request to the server for comparison.
If the server finds that the file is unmodified (i.e., the current modified date is same as the one in the request), the server sends a Not-Modified (status code: 304) header instead of the OK header (status code: 200). So, the browser can continue to serve the file from the cache until the cache expires once again.
Else, if the file is modified, the server sends the new date inside the Last-modified header along with the new content. The browser downloads it and keep it in the cache.
ETag or Entity Tag
Instead of a date and time, the ETag header sends a hashed value. When a file is modified, the ETag value also changes. Some sources say that ETag is more dependable than Last-modified.
The remaining logic is same as that of Last-modified. The server compares the the current ETag value with the one from the client for validating the cache.
Issue with ETag Header
According to Yahoo Developer Network, ETag may not work as expected if your site uses more than one server as in a load balancer.
The reason is if Apache includes the Inode number while calculating the ETag. The Inode may be different for each server, resulting in different ETag values.
To ensure Inode is omitted, set:
FileETag MTime Size # Default is FileETag INode MTime Size
For those who use only one server to host a site, this is not an issue at all.
So, the final code to add in your .htaccess file is here. It is based on the code generated by the W3 Total Cache Plugin.
In the above code, note that the ExpiresByType directive sets both the Expires and Cache-control max-age headers [source].
So, here is the summary of what we have discussed above:
- Leveraging browser cache means asking the browser to store resources in its cache for a period of time. It prevents repetitive requests to the server until the cache expiration time is reached.
- Cache-control (max-age) and Expires headers set the expiry/lifetime of a cached resource.
- Last-modified and ETag headers allow revalidating an expired cache item
- Cache-control and ETag are preferred than Expires and Last-modified, although you can set all of them.