11

I am hosting a web app on Azure with the following Web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <staticContent>
      <mimeMap fileExtension=".text" mimeType="text/plain" />
      <clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
    </staticContent>
  </system.webServer>
</configuration>

This works but I would like to vary the cache age by extension. I would like to set the max age of .html files to 1 day and the max age of everything else to 365 days. The reason being that all of the assets in the html have their filenames revved on change and are served from a CDN, so they never need to expire, but the html pages themselves need to always be fresh so the user can see new content.

I see that the <location> element allows filtering the Web.config to specific locations, but I don't see a way to limit it to certain extensions.

Please note that I don't require being able to do this in the Web.config: any means possible with an Azure Web App is fine.

Alan
  • 408
  • 3
  • 12

3 Answers3

22

As others have mentioned it is not possible so I would like to suggest a workaround to do the job.
You can take advantage of the capabilities of the URL Rewrite Module by creating an outbound rule to replace Cache-Control header of the html files.

Here's the config.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <staticContent>
            <mimeMap fileExtension=".text" mimeType="text/plain" />
            <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" />
        </staticContent>
        <rewrite>
            <outboundRules>
                <rule name="RewriteCacheControlForHTMLFiles" preCondition="FileEndsWithHtml">
                    <match serverVariable="RESPONSE_Cache_Control" pattern=".*" />
                    <action type="Rewrite" value="max-age=86400" />
                </rule>
                <preConditions>
                    <preCondition name="FileEndsWithHtml">
                        <add input="{REQUEST_FILENAME}" pattern="\.html$" />
                    </preCondition>
                </preConditions>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>

A screenshot of my test:

enter image description here

Kul-Tigin
  • 16,728
  • 1
  • 35
  • 64
  • The workaround suggested below to move my content around would have worked as well, but this was much simpler and less work. Thanks! – Alan May 05 '16 at 01:41
  • This worked for me after hours of searching for this solution on Google. Finally found it! – Anil Gupta Jun 29 '18 at 03:31
3

Are these files (html vs content) in separate folders? If so, you can setup a folder specific caching age

<configuration>
<location path="[html files path]">
    <system.webServer>
      <staticContent>
        <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="[your requirement]" ></clientCache>
      </staticContent>
    </system.webServer>
  </location>
</configuration>
Gandhali Samant
  • 877
  • 4
  • 10
  • No, they're all intermingled. E.g. there's /articles/article1/index.html and /articles/article1/figure1.png – Alan Apr 28 '16 at 14:16
1

Unfortunately the <location> element doesn't support regex or wildcards so you won't be able to do exactly what you are asking.

I can think of a couple of ways to achieve your goal though. The first is to write an http module that intercepts requests to images and changes the caching headers.

The other option is to leave your html unchanged but to move all your images to an images folder. You could then set a caching rule on that folder. You could use a redirect rule to redirect requests for images to that images folder. If you choose this path I can give you more information about how you might set it up.

Community
  • 1
  • 1
Sudsy
  • 931
  • 7
  • 16
  • If I made all CDN requests come in under a subdirectory, would it be possible to have a cache rule for that subdirectory and then rewrite away the subdirectory? For example: 1. request comes in to host.com/CDN/articles/article1/foo.jpg 2. request gets long cache expiration applied 3. request gets rewritten to host.com/articles/article1/foo.jpg 4. foo.jpg gets served up from /articles/article1 – Alan May 01 '16 at 10:52
  • 1
    I don't think this will work because of [the way IIS handles rewrites](http://www.iis.net/learn/extensions/url-rewrite-module/iis-url-rewriting-and-aspnet-routing). Rewrites happen very early on in the request processing pipeline. As far as the lower parts of the pipeline are concerned, the request is coming from the rewritten url and so you end up with the same problem. Is it not practical to have a build step that moves all the images to a different folder? – Sudsy May 02 '16 at 23:08
  • Thank you for taking the time to reply and saving me the trouble of attempting this. It would be possible to move all assets into a single top-level folder, e.g. "move all images to /images," and so on for all asset types, but it would be practical to move all assets into subfolders that represent their grouping. E.g. I would have to move host.com/CDN/articles/article1/foo.jpg into cdn.host.com/images/foo.jpg, because anything else would involve ALSO modifying the HTML to point at the new location. Which is also totally doable but annoying. – Alan May 05 '16 at 01:27
  • I meant to say "but it would be **im**practical to move all assets into subfolders that represent their grouping" – Alan May 05 '16 at 01:40
  • Up to you what directory structure you want in the destination You could have a rewrite rule that did either - /articles/article1/foo.jpg to /images/foo.jpg or - /articles/article1/foo.jpg to /images/articles/article1/foo.jpg to /images/foo.jpg whatever works for you. In either case you won't have to change your html and the client won't be redirected, it will still look like the image comes from the original location. – Sudsy May 05 '16 at 02:47