Cache Single Page Applications (SPA) in Internet Information Service (IIS)

For a job I was tasked to solve a caching problem for the Angular App of the customer. After a roll out endusers would complain about a broken app or weird bugs. Most of the time a flushing of the browser cache on the enduser side solved the situation. To reduce the stress for the user (and the support of the customer) we had to fix this situation.

Starting situation

An Angular 7 App which is hosted on IIS 10. The Javascript bundles are cachebusted (runtime.125e6789f09876a5432...b778.js) but the index.html which references the *.js files is not. On initial load (and after cache flushing) the index.html is requested by the browser and delivered. All references (javascript files, css, cat pictures) are then resolved and requested accordingly.

As no caching was setup in the IIS so far, the browsers took educated guesses what to cache for how long. Static html files for example? The usualy don’t change, thats why they are static. This results in an old frontend getting data from a (potentially) newer API.

Solution

Check in a web.config and roll it out togetehr with your app (in the output folder in the IIS). Set the cacheControlMaxAge header to a reasonable big time and add a outbound rewrite rule to replace this time for *.html files with 0.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <staticContent>
            <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=0" />
                </rule>
                <preConditions>
                    <preCondition name="FileEndsWithHtml">
                        <add input="{REQUEST_FILENAME}" pattern="\.html$" />
                    </preCondition>
                </preConditions>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>

This way, browser don’t cache *.html files but will cache all other files for a year

Remarks

The IIS “Output Caching” module which actually can handle be setup for specific filetypes has nothing to do with the browser cache. This setting “only” determines how the IIS caches files internally (so it does not have to do a disk access)

Source

I found this piece of code on this answer by Kul-Tigin on Stackoverflow