Cache busting in IIS using query string for static content - caching

my site is a static site and I serve the content from a IIS 8 web server. I used to use Apache and I have the following configuration for cache busting, which I'd like to implement in IIS:
# Extend cache expiry for fingerprinted URLs
RewriteCond %{QUERY_STRING} ^[0-9a-fA-F]{8,}$
RewriteRule ^ - [E=revved:1]
And then I set Cache-Control based on whether the environment variable "revved" is set:
# (For HTTP/1.1 clients)
Header set Cache-Control "max-age=1200" env=!revved
Header set Cache-Control "max-age=31536000" env=revved
My JS and CSS is bundled and I attach the hash to the query string. I do the same for images.
So far what I have been available to do is use the <clientCache /> element and attach cacheControlMode="UseMaxAge and cacheControlMaxAge="00:20:00" to it.
What you can see in the Apache config is that when the "revved" variable is set then the proxy server (CDN) and the client should cache the files for 365 days. Otherwise, it should only cache for 20 minutes. I'd like to have the same behaviour in my web.config.
I read about "Output Caching" in IIS, but from what I understand that is designed for dynamic pages using PHP or ASP.
I would be very grateful, if someone can guide me in the right direction.

I believe that I came up with a solution that is working. I got some hints from this post on MSDN "Change or modify a Response Header value using URL Rewrite".
<outboundRules>
<rule name="ChangeCacheControlHeaderOneYear">
<match serverVariable="RESPONSE_CacheControl" />
<conditions>
<add input="{QUERY_STRING}" pattern="^[0-9a-fA-F]{8,}$" />
</conditions>
<action type="Rewrite" value="max-age=31536000" />
</rule>
<rule name="ChangeCacheControlHeader20Minutes">
<match serverVariable="RESPONSE_CacheControl" />
<conditions>
<add input="{QUERY_STRING}" pattern="^[0-9a-fA-F]{8,}$" negate="true" />
</conditions>
<action type="Rewrite" value="max-age=1200" />
</rule>
</outboundRules>

Related

Why Aren't My URL Rewrite Maps Changing the Browser's URL?

Environment
IIS Server 8
URL Rewrite Module 2.0 (Version 7.2.2; Microsoft)
Rewrite Maps
Static HTML Files
Background
I want to display a user-friendly URL in the Browser by using URL Rewrite Mapping.
Problem
The Browser's URL bar does not change (ie, it does not switch to the user-friendly URL).
Request
Can you please tell me how to get my URL Rewrite Mapping to actually re-write the browser's URL (to the mapped value)?
Sample Code (Web.Config)
<rule name="RewriteMapping" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{Test:{REQUEST_URI}}" pattern="(.+)" />
</conditions>
<action type="Rewrite" url="{C:1}" appendQueryString="false" />
</rule>
<rewriteMaps>
<rewriteMap name="Test" defaultValue="">
<add key="foo.html" value="This-Is-A-Nice-Page-To-Remember" />
</rewriteMap>
</rewriteMaps>
To "rewrite" new canonical URLs to the underlying file
You have created a rewrite map that internally rewrites the "pretty" requested URL to the underlying URL/file that handles the request. Although you appear to have written the key/value pair the wrong way round. It should be:
<add key="/This-Is-A-Nice-Page-To-Remember" value="/foo.html" />
/This-Is-A-Nice-Page-To-Remember is the "pretty" URL being requested, and /foo.html is the underlying file that the request is rewritten to that actually handles the request.
This is not an external redirect that "changes" the URL in the browser. You need to actually change the URLs in your HTML source. The rewrite map does not do this for you (and neither is it meant to).
The rewrite map as written probably isn't actually doing anything (missing slash prefix), but if it did then it would presumably result in a 404 since This-Is-A-Nice-Page-To-Remember won't be recognised as a valid page.
To "redirect" old URLs to new
However, if you are changing an existing URL structure then you can implement an additional "redirect" rewrite map to externally redirect requests for the "old" URL to the desired "pretty" canonical URL (essentially the reverse of the above). But you must have already changed the URLs in your HTML source before doing so. This "redirect" rewrite map is simply to preserve SEO and to ensure that any inbound links from other sites are not broken. If you don't change the URLs in your HTML source, then users still see (and are able to copy) the "old" (non-canonical) URLs and every time the user clicks a link they will be externally redirected (doubling the requests to your server and slowing the user).
For example, to implement a "redirect" rewrite map from the "old" to "new" (canonical) URL, create an additional rewrite map:
<rules>
<rule name="CorrectOldURLs" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{OldRedirects:{REQUEST_URI}}" pattern="(.+)" />
</conditions>
<action type="Redirect" url="https://example.com{C:1}" appendQueryString="False" redirectType="Permanent" />
</rule>
</rules>
<rewriteMaps>
<rewriteMap name="OldRedirects">
<add key="/foo.html" value="/This-Is-A-Nice-Page-To-Remember" />
</rewriteMap>
</rewriteMaps>
If this is a new site, then this "redirect" rewrite map is not strictly necessary, since the underlying files should never be exposed.
In Summary
Bringing the above two together, we have:
<rules>
<rule name="RewriteMapping" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{Test:{REQUEST_URI}}" pattern="(.+)" />
</conditions>
<action type="Rewrite" url="{C:1}" appendQueryString="false" />
</rule>
<rule name="CorrectOldURLs" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{OldRedirects:{REQUEST_URI}}" pattern="(.+)" />
</conditions>
<action type="Redirect" url="https://example.com{C:1}" appendQueryString="False" redirectType="Permanent" />
</rule>
</rules>
<rewriteMaps>
<rewriteMap name="Test" defaultValue="">
<add key="/This-Is-A-Nice-Page-To-Remember" value="/foo.html" />
</rewriteMap>
<rewriteMap name="OldRedirects">
<add key="/foo.html" value="/This-Is-A-Nice-Page-To-Remember" />
</rewriteMap>
</rewriteMaps>
But to emphasise again, as stated above, you must have manually changed the URLs in the HTML source before implementing this. There is no shortcut here.
Reference:
https://learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/using-rewrite-maps-in-url-rewrite-module

How to write IIS rewrite rule to redirect request to different server?

I have my main website running at a hosting company with IIS 7.5 at http://example.com
I'm setting up a WordPress blog at the same hosting company on a Linux, Apache, PHP machine.
When a user types in "http://example.com/blog" I want to redirect the request to the WordPress site.
To the end user they wouldn't know the blog content is being served up from a different server.
What is the specific IIS rewrite rule needed to do this?
<rewrite>
<rules>
<rule name="Redirect" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^www.mysite1.com$" />
</conditions>
<action type="Redirect" url="www.mysite2.com" />
</rule>
</rules>
</rewrite>

IIS Url rewrites with Sitecore

I'm using the IIS URL rewrite add-on in my Sitecore v7.2 website to handle redirects.
I've setup the Rewrites on the website node in IIS and not on the top level IIS server.
These are simple redirects such as appending a slash in certain situations
<rule name="CA Redirect" stopProcessing="true">
<match url="^ca$" />
<action type="Rewrite" url="{R:0}/" />
</rule>
I'm finding that unless I add the path e.g. "/ca" to the IgnoreUrlPrefixes in Sitecore IIS will not process the redirect, and it appears that Sitecore is handling the request before the URL rewrite rule.
Has anyone else come across this issue? Should the rules be added at the top level rather than the website level?
We're using redirects at website level and it works without problems. IIS is redirecting before Sitecore handles the request.
Doing it at site level is generating this in the web.config
<rewrite>
<rules>
<rule name="Web closed" enabled="true" stopProcessing="true" patternSyntax="Wildcard">
<match url="*" />
<action type="Rewrite" url="/holdingpage.html" logRewrittenUrl="true" redirectType="Temporary" />
</rule>
</rules>
</rewrite>

Url rewrite for outbound rules causing infinite redirect on Windows Server 2012 / IIS 8

I have a Windows Server 2012 instance running IIS 8.
We are hosting a .NET 4.0 website trying to use an outbound rewrite rule to fetch CDN assets.
The presence of the outboundRules tag in the web.config seems to throw the site into an endless redirect loop. The site performs perfectly without the outboundRules tag. I have included the actual rewrite rule we are using but even including the outboundRules tag with nothing in it can cause the site to end up non responsive.
We have confirmed that static compression is not enabled for the site which is what a few other posts around the web have referenced but that does not seem to resolve our situation.
<outboundRules>
<preConditions>
<preCondition name="ExcludeAXD">
<add input="{URL}" pattern=".axd" negate="true" />
<add input="{URL}" pattern=".asmx" negate="true" />
<add input="{URL}" pattern=".ashx" negate="true" />
</preCondition>
</preConditions>
<rule name="CDNRule" enabled="true" preCondition="ExcludeAXD"
stopProcessing="true">
<match filterByTags="Img, Input, Script, Link"
pattern="(^.*?(?=/mymediafoldercontainingassets))(.*)" />
<action type="Rewrite" value="{R:1}http://subdomain.mycdn.com{R:2}" />
</rule>
</outboundRules>
Any help would be greatly appreciated,

Rewriting Subdomains in IIS

I'm having some trouble rewriting some things in IIS
Here is what I'm trying to achieve.
We have a bunch of clients that all need a subdomain. For example
http://clientA.mysite.com needs to be rewritten to http://mysite.com/clientArea/?clientID=1234
Then all content needs to be rewrriten to http://mysite.com/clientArea/XXX
so for example if someone requests http://clientA.mysite.com/example.css , that should be rewritten to http://mysite.com/clientArea/example.css
I cannot for the life of me get this working right.
I think I have to to do this in 2 rules. I think I have the first rule working kindof (page looks whack because it can't get the JS files or CSS files to make it look right)
Here is my first rule to rewrite http://clientA.mysite.com to http://mysite.com/clientArea/?clientID=1234
<rule name="Rewrite Subdomain" stopProcessing="true">
<match url="()" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(?!www)clientA\.mysite\.com$" />
</conditions>
<action type="Rewrite" url="clientArea/?clientID=1234" appendQueryString="true" logRewrittenUrl="true" />
</rule>
My second rule, however, I cannot get to work, so any help with this would be great
<rule name="Rewrite Everything Else after subdomain">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(?!www)clientA\.mysite\.com$" />
</conditions>
<action type="Rewrite" url="{R:0}" />
</rule>
Requesting things like http://clientA.mysite.com/example.js returns a 404 error.
Thanks for the time,
Kyle
If you have dedicated IP number for your site, you can add empty http binding to your site in IIS (right click on your site in IIS > Edit bindings > Add). Then add DNS 'A' record with value: * in your DNS configuration. As a result, every call to your IP will be maintained by your site.
You use a combination in inbound and outbound rewritting rules along with the Application Request Routing Module.
Inbound rule proxies the subfolder to the subdomain content. Outbound rule examines the response and replaces all instances of the subdomain in the response with your subfolder path.

Resources