Are you caching your images and scripts? IIS SEO can tell you


One easy way to enhance the experience of users visiting your Web site by increasing the perceived performance of navigating in your site is to reduce the number of HTTP requests that are required to display a page. There are several techniques for achieving this, such as merging scripts into a single file, merging images into a big image, etc, but by far the simplest one of all is making sure that you cache as much as you can in the client. This will not only increase the rendering time but will also reduce load in your server and will reduce your bandwidth consumption.


Unfortunately the different types of caches and the different ways of set it can be quite confusing and esoteric. So my recommendation is to think about one way and use that all the time, and that way is using the HTTP 1.1 Cache-Control header.


So first of all, how do I know if my application is being well behaved and sending the right headers so browsers can cache them. You can use a network monitor or tools like Fiddler or wfetch to look at all the headers and figure out if the headers are getting sent correctly. However, you will soon realize that this process won’t scale for a site with hundreds if not thousands of scripts, styles and images.


Enter Site Analysis – IIS Search Optimization Toolkit


To figure out if your images are sending the right headers you can follow the next steps:



  1. Install the IIS Search Optimization Toolkit from http://www.iis.net/extensions/SEOToolkit

  2. Launch InetMgr.exe (IIS Manager) and crawl your Web Site. For more details on how to do that refer to the article “Using Site Analysis to crawl a web site“.

  3. Once you are in the Site Analysis dashboard view you can start a New Query by using the Menu “Query->New Query” and add the following criteria:

    1. Is External – Equals – False -> To only include the files that are coming from your Web site.

    2. Status code – Equals – OK -> To include only successful requests

    3. Content Type Normalized – Begines With – image/ -> To include only images

    4. Headers – Not Contains – Cache-Control: -> to include the ones does not have the cache-control header specified

    5. Headers – Not Contains – Expires: -> To include only the ones that do no have the expires header

    6. Press Execute, and this will display all the images in your Web site that are not specifying any caching behavior.

Alternatively you can just save the following query as “ImagesNotCached.xml” and use the Menu “Query->Open Query” for it. This should make it easy to open the query for different Web sites or keep testing the results when making changes:


<?xml version=”1.0″ encoding=”utf-8″?>
<query dataSource=”urls”>
 
<filter>
   
<expression field=”IsExternal” operator=”Equals” value=”False” />
    <
expression field=”StatusCode” operator=”Equals” value=”OK” />
    <
expression field=”ContentTypeNormalized” operator=”Begins” value=”image/” />
    <
expression field=”Headers” operator=”NotContains” value=”Cache-Control:” />
    <
expression field=”Headers” operator=”NotContains” value=”Expires:” />
  </
filter>
 
<displayFields>
   
<field name=”URL” />
    <
field name=”ContentTypeNormalized” />
    <
field name=”StatusCode” />
  </
displayFields>
</query>

How do I fix it?


In IIS 7 this is trivial to fix, you can just drop a web.config file in the same directory where your images and scripts and CSS styles specifying the caching behavior for them. The following web.config will send the Cache-Control header so that the browser caches the responses for up to 7 days.


<?xml version=”1.0″ encoding=”UTF-8″?>
<configuration>
 
<system.webServer>
       
<staticContent>
           
<clientCache cacheControlMode=”UseMaxAge” cacheControlMaxAge=”7.00:00:00″ />
        </
staticContent>
 
</system.webServer>
</configuration>

You can also do this through the UI (IIS Manager) by going into the “HTTP Response Headers” feature -> Set Common Headers… or any of our API’s using Managed code, JavaScript or your favorite language:



http://www.iis.net/ConfigReference/system.webServer/staticContent/clientCache


Furthermore, using the same query above in the Query Builder you can Group by Directory and find the directories that really worth adding this. For that is just matter of clicking the “Group by” button and adding the URL-Directory to the Group by clauses. Not surprisingly in my case it flags the App_Themes directory where I store 8 images.


IIS SEO


 


Finally, what about 304’s?


One thing to note is that that even if you do not do anything most modern browsers will use conditional requests to reduce the latency if they have a copy in their cache, as an example, imagine the browser needs to display logo.gif as part of displaying test.htm and that image is available in their cache, the browser will issue a request like this


GET /logo.gif HTTP/1.1
Accept: */*
Referer: http://carlosag-client/test.htm
Accept-Language: en-us
User-Agent: (whatever-browser-you-are-using)
Accept-Encoding: gzip, deflate
If-Modified-Since: Mon, 09 Jun 2008 16:58:00 GMT
If-None-Match: “01c13f951cac81:0”
Host: carlosagdev:8080
Connection: Keep-Alive

Note the use of If-Modfied-Since header which tells the server to only send the actual data if it has been changed after that time. In this case it hasn’t so the server responds with a status code 304 (Not Modified)


HTTP/1.1 304 Not Modified
Last-Modified: Mon, 09 Jun 2008 16:58:00 GMT
Accept-Ranges: bytes
ETag: “01c13f951cac81:0”
Server: Microsoft-IIS/7.0
X-Powered-By: ASP.NET
Date: Sun, 07 Jun 2009 06:33:51 GMT

Even though this helps you can imagine that this still requires a whole roundtrip to the server which even though will have a short response, it can still have a significant impact if rendering of the page is waiting for it, as in the case of a CSS file that the browser needs to resolve to display correctly the page or an <img> tag that does not include the dimensions (width and height attributes) and so requires the actual image to determine the required space (one reason why you should always specify the dimensions in markup to increase rendering performance).


Summary


To summarize, with IIS Search Engine Optimization Toolkit you can easily build your own queries to learn more about your own Web site, allowing you to easily find details that otherwise were tedious tasks. In this case I show how easy it is to find all the images that are not specifying any caching headers and you can do the same thing for scripts (if you add Content Type Normalized equals application/javascript)  or styles (Content Type Normalized Equals text/css). This way you can increase the performance of the rendering and reduce the overall bandwidth of your Web site.

Comments (3)

  1. Peter Gfader says:

    >In IIS 7 this is trivial to fix

    What about IIS 6?

    Can you post some instructions please?

    Thanks

  2. moscheIT says:

    I agree with @Peter please some instructions for IIS 6

    Thanks

  3. Manoj Barik says:

    OK. Are you sold on the idea yet? If so, here’s how to adjust this setting in IIS 7.5 (Windows Server 2008 R2 hosting)…

    First open the IIS Manager on your server, expand the Sites folder and then find the site you want to manage. You can control the caching either for the entire site or for specific folders. The interface and steps are basically the same, but I’ll show screenshots of making the change just on the images folder of my test site:

    Compression setting in IIS

    Once you select the folder you’ll see a bunch of standard option icons. You want to look for the HTTP Response Headers icon in the IIS section of the IIS Manager interface. I’ve highlighted it in red above.

    Once you double-click on that icon you’ll see the interface change:

    Set Common Headers in IIS

    From this interface you’ll want to select the option in the right-hand pane to Set Common Headers. Clicking that link brings up a dialog box to set just two common header items with a few option settings:

    The Common Header settings and options in IIS

    The HTTP Keep-alive should be already selected by default – leave that alone. Let’s pay attention to the Expire Web Content option which isn’t selected by default. Once you check that box you’ll see that it defaults to expiring the content immediately… which is not helpful at all. Choose the radio button for “After” then set a date range. Google seems to prefer this caching option set to at least one week so I commonly set it to 8 days as shown in my sample image.

    Click OK to save the settings and you’re all done! You can test your site using browser (IE or Chrome) developer tools to confirm the headers, or use an external testing site to confirm the caching.

    I hope you find this helpful – Happy Hosting!