Using CDNs and Expires to Improve Web Site Performance
Much has been written on the advantages of using a Content Delivery Network (CDN) to deliver static content ( jQuery, images, CSS files, etc.). (If you’re not familiar with CDNs, read ScottGu’s blog post Announcing the Microsoft AJAX CDN and Microsoft Ajax Content Delivery Network ) But the biggest advantages of CDNs are often overlooked:
- Many major sites use the Microsoft CDN, so there’s a good chance your customers browsers cache already contains jQuery from the CDN. If another site has loaded your jQuery version from the Microsoft CDN, and your web site requests that version from the Microsoft CDN, the client cache can satisfy the request, eliminating the download cost.
- Once content is loaded from the CDN, future requests don’t incur the round trip cost of checking with the server if the content is current. That is, the client avoids the HTTP 304.
- Server Farms don’t need to coordinate the ETag cache validator.
Quick review of browser caching
There are two principal mechanisms to browser caching:
- Validate the requested resource in the browser cache is the same as on the server. If the resource is the same, the server can send back a HTTP 304 response, eliminating the need to send a response body with the content. Many people consider HTTP 304’s a good thing since they eliminate the need to send a full response body. I’ll show they are often an drag on performance, because the involve an unnecessary round trip to the server.
- Freshness: If the resource in the cache is fresh, pull the resource from the cache without checking with the server.
The freshness heuristic is not met (that is, the file in the cache is not considered fresh).
You have changed the expires header or other caching header.
You have set the browser to disable caching..
The URL to the resource changes or is different. For example, the following URLs are all pointing to the same modernizr script, but because each URL is different, each resource must be downloaded.
The first and last modernizer files were served by Cassini (The default Visual Studio Web Server) or IIS Express, that’s why we see the port number. The middle two were served by the local machines IIS server, but using two different host names (localserver and the actual name, q1). You can examine the IE9 cache by selecting the Settings button under Browsing history on the General tab, then selecting View Files.
Each browser has its own cache, so FireFox won’t use files cached by Chrome or IE.
The following image shows a Fiddler session of browsing to my Movie site. Because I hadn’t browsed to the Movie site in several days, IE9 was forced to validate the modernizr and the custom jQuery file.
Selecting the Caching Tab in Fiddler gives the details on why validation was necessary and how much longer browsers will server these files directly without server validation. In the example below, for the next 2 days, 19 hours and 20 minutes, IE9 will pull the resource directly from the cache without checking with the server (and saving the HTTP 304 round trip). The Caching Inspector in Fiddler will show you when a response expires, based on the headers provided on that response. For instance, here’s the default response from IIS 7.5 which contains an ETAG and Last-Modified header, but no expiration information:
The No Explicit HTTP Expiration information was provided message is a good hint of what you need to do, explicitly set the expiration. Best practices recommend that web developers should specify an explicit expiration time for their content several years out in order to ensure that the browser is able to reuse the content without making conditional HTTP requests to revalidate the content with the server. If the resource changes, change the name of the resource. The following markup shows the contents of a Web.config file added to the Content and Scripts folders.
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <staticContent> <clientCache cacheControlMode="UseExpires" httpExpires="Mon, 06 May 2013 00:00:00 GMT" /> </staticContent> </system.webServer> </configuration>
This sets the Expires Header out a couple years. Using ^R in the IE9 F-12 developer tools, clear the cache, then browse to the Movie site. Using Fiddler we can see the Expires Header will allow IE9 to serve this file directly from the cache without checking with the server for the next two years.
Using Fiddler and the IE9 F12 Developer tools to monitor browser requests.
From IE9, hit F12 to start the F12 developer tools, then clear the cache.
In the IE9 F12 tools, select the Network tab, then select Start capturing. Select Home or About in the Movie application.
Fiddler correctly shows IE did not make a conditional requests for the static resources, that is, there are no HTTP GET requests from IE and no HTTP 304 responses from the server. Why is IE9 showing GET requests made by IE9 and the server returning 304’s? Eric Lawrence explains why 13 minutes into his presentation Debugging with Fiddler. It is difficult, at the level that the F12 Network Monitor is installed, to determine whether a given “from cache” response was “PreNetIO” (e.g. fresh in the local cache) or “PostNetIO” (e.g. in the local cache but a conditional HTTP request was used to validate freshness). Hence, sometimes F12 will show misleading “(304)”s when it meant “(cache)”.
Firebug is actually worse, showing expensive HTTP 200 results for each of the static resources.
Chrome developer tools correctly show each resource coming from the cache.
A Simple Helper to Load Resources in ASP.NET MVC Projects
The following code shows the layout file in my modified MVC Movie project which uses the LoadRes helper to load static and CDN resources.
I use my LoadRes helper to clean up the markup used to load resources.
Special thanks to Erick Lawrencefor answering questions. Much of the information came from his blog.
- Understanding Conditional Requests and Refresh (Erick Lawrence)
- Caching Improvements in Internet Explorer 9 (Erick Lawrence)
- best-practices for performance
- IE 9 F12 Developer Tools User Interface Reference
- IE 9 How to use F12 Developer Tools to Debug your Webpages
- Best Practices for Speeding Up Your Web Site
- The Devil Went Down to HTTP: Debugging with Fiddler Video by Eric Lawrence 13 min into it he explains the 304’s
- Caching in HTTP