101

I'm trying to do something which I thought would be fairly simple. Get IIS 7 to tell clients they can cache all images on my site for a certain amount of time, let's say 24 hours.

I have tried the step on http://www.galcho.com/Blog/post/2008/02/27/IIS7-How-to-set-cache-control-for-static-content.aspx but to no avail. I still get requests going to the server with 304s being returned.

Does anyone have a way of doing this? I have a graphically intensive site and my users are being hammered (so is my server) every time they request a page. Wierdly the images seem to have "Cache-Control private,max-age=3600" showing up in Firebug but the browser is still requesting them when I press F5.

Rob W
  • 341,306
  • 83
  • 791
  • 678
Chris Meek
  • 5,720
  • 9
  • 35
  • 44

6 Answers6

132

If you want to set the Cache-Control header, there's nothing in the IIS7 UI to do this, sadly.

You can however drop this web.config in the root of the folder or site where you want to set it:

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

That will inform the client to cache content for 7 days in that folder and all subfolders.

You can also do this by editing the IIS7 metabase via appcmd.exe, like so:

\Windows\system32\inetsrv\appcmd.exe 
  set config "Default Web Site/folder" 
  -section:system.webServer/staticContent 
  -clientCache.cacheControlMode:UseMaxAge

\Windows\system32\inetsrv\appcmd.exe 
  set config "Default Web Site/folder" 
  -section:system.webServer/staticContent 
  -clientCache.cacheControlMaxAge:"7.00:00:00"
Jeff Atwood
  • 63,320
  • 48
  • 150
  • 153
  • 5
    The MSDN documentation for staticContent configuration element can be found here: http://msdn.microsoft.com/en-us/library/ms689443.aspx – Milan Gardian Dec 18 '09 at 05:46
  • 4
    See 360Airwalk posts below, there is UI for this in IIS7 – ChadT Jul 07 '10 at 07:29
  • Just as an info: this setting seems to have no effect on the built-in Development Server (of VS 2010 SP1 at least). If in doubt why it doesn't work, check with the IIS. –  Apr 19 '11 at 16:32
  • 7
    Hi Jeff, are you aware of how to serve different `Cache-Control` (`max-age`) headers for different mime-types or files extensions? – Jasper Apr 04 '12 at 00:25
  • @Jeff Atwood Maybe you can help me. Look at this : https://stackoverflow.com/questions/57990579/how-long-does-it-take-for-the-script-caching-to-work – moses toh Sep 18 '19 at 12:00
118

That's not true Jeff.

You simply have to select a folder within your IIS 7 Manager UI (e.g. Images or event the Default Web Application folder) and then click on "HTTP Response Headers". Then you have to click on "Set Common Header.." in the right pane and select the "Expire Web content". There you can easily configure a max-age of 24 hours by choosing "After:", entering "24" in the Textbox and choose "Hours" in the combobox.

Your first paragraph regarding the web.config entry is right. I'd add the cacheControlCustom-attribute to set the cache control header to "public" or whatever is needed in that case.

You can, of course, achieve the same by providing web.config entries (or files) as needed.

Edit: removed a confusing sentence :)

Edward Brey
  • 40,302
  • 20
  • 199
  • 253
360Airwalk
  • 2,189
  • 1
  • 16
  • 13
  • 1
    The UI for this setting is terrible. But thanks for explaining how to get there! +1 – Billy Coover Oct 20 '10 at 03:14
  • This interface creates a web.config with the same configuration as Jeff posted. Nice to know! Thanks! – RandyMorris Jul 25 '11 at 01:12
  • 2
    Thanks for the post @360Airwalk. Are you aware of how to serve different `Cache-Control` (`max-age`) headers for different mime-types or files extensions? – Jasper Apr 04 '12 at 00:25
  • 3
    @Jasper: you can set it per folder for example. if you set the cache-control on a folder subfolders will inherit the setting but you can override it again and so on. you can even do it on a per-file-basis. if you cant access the iis console you can do it via web.config as well. see this post for the latter http://stackoverflow.com/questions/2195266/how-to-configure-static-content-cache-per-folder-and-extension-in-iis7 – 360Airwalk Apr 04 '12 at 14:18
29

I use this

<staticContent>
<clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="500.00:00:00" />
</staticContent>

to cache static content for 500 days with public cache-control header.

Eonasdan
  • 7,563
  • 8
  • 55
  • 82
Elmer
  • 9,147
  • 2
  • 48
  • 38
  • 10
    Recommended practice is 1 year essentially 365 days no more. – Anicho Jun 20 '12 at 13:55
  • 5
    500 days is BAD, that articles talks about an RFC rule telling to not set the cache to more than 1 year https://developers.google.com/speed/docs/best-practices/caching Do not set it to more than one year in the future, as that violates the RFC guidelines. – foxontherock Jun 26 '13 at 13:13
  • @foxontherock any way you could substantiate the RFC rule of more than 365 days being bad practice? I cannot find anything to suggest this in the documentation... – Paesano2000 Nov 13 '18 at 19:14
  • @Elmer Maybe you can help me. Look at this : https://stackoverflow.com/questions/57990579/how-long-does-it-take-for-the-script-caching-to-work – moses toh Sep 18 '19 at 12:00
21

Complementing Elmer's answer, as my edit was rolled back.

To cache static content for 365 days with public cache-control header, IIS can be configured with the following

<staticContent>
    <clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" />
</staticContent>

This will translate into a header like this:

Cache-Control: public,max-age=31536000

Note that max-age is a delta in seconds, being expressed by a positive 32bit integer as stated in RFC 2616 Sections 14.9.3 and 14.9.4. This represents a maximum value of 2^31 or 2,147,483,648 seconds (over 68 years). However, to better ensure compatibility between clients and servers, we adopt a recommended maximum of 365 days (one year).

As mentioned on other answers, you can use these directives also on the web.config of your site for all static content. As an alternative, you can use it only for contents in a specific location too (on the sample, 30 days public cache for contents in "cdn" folder):

<location path="cdn">
   <system.webServer>
        <staticContent>
             <clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="30.00:00:00"/>
        </staticContent>
   </system.webServer>
</location>
Luciano Carvalho
  • 1,739
  • 15
  • 15
  • Luciano, I am trying to cache my images using your method. Now when I analyze using HttpFox I see 2 requests made for each image. 1. First one gives an aborted result with (NS_BINDING_ABORTED) error 2. second request is a cached image. Any thoughts? – Mithil May 02 '13 at 21:09
19

The F5 Refresh has the semantic of "please reload the current HTML AND its direct dependancies". Hence you should expect to see any imgs, css and js resource directly referenced by the HTML also being refetched. Of course a 304 is an acceptable response to this but F5 refresh implies that the browser will make the request rather than rely on fresh cache content.

Instead try simply navigating somewhere else and then navigating back.

You can force the refresh, past a 304, by holding ctrl while pressing f5 in most browsers.

AnthonyWJones
  • 187,081
  • 35
  • 232
  • 306
1

there is a easy way: 1. using website's web.config 2. in "staticContent" section remove specific fileExtension and add mimeMap 3. add "clientCache"

<configuration>
  <system.webServer>
    <urlCompression doStaticCompression="true" doDynamicCompression="true" />
    <staticContent>
      <remove fileExtension=".ipa" />
      <remove fileExtension=".apk" />
      <mimeMap fileExtension=".ipa" mimeType="application/iphone" />
      <mimeMap fileExtension=".apk" mimeType="application/vnd.android.package-archive" />
      <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="777.00:00:00" />
    </staticContent>
  </system.webServer>
</configuration>