AngularJS, HTML 5 Mode, IIS (Express) and hitting F5/Refresh

Using AngularJS in HTML 5 URI mode with IIS

The company I joined in November (more about this another day!) has a product that was developed in AngularJS 1.x. Not AngularAngularJS - one of these things is not like the other! This means that I've had a new framework to get a handle on, along with understanding the business, the people and everything else.

One of the things I dislike, though that's perhaps too strong a word, is the way paths inside an AngularJS single page application form part of the fragment part of the URI, rather than the "real" path. One of the things I've discovered whilst digging around in AngularJS is the fact that it can take advantage of the HTML 5 History API in its "HTML 5 Mode" feature. This means that it'll transform the URLs in the address bar from ones that look like https://example.org/index.html#/path/to/a/part/of/the/app to https://example.org/path/to/a/part/of/the/app. The reason that this interested me is I immediately wondered what would happen if you pressed F5, i.e. the server ends up being given a path it doesn't know about. When I say wondered, I knew exactly what would happen but wanted to work out what the solution was.

In IIS (or IIS Express under development) the solution is to use the URL Rewrite feature to map any requests for URLs that don't physically exist back to the root of your application. This ensures that they get handed back off to your AngularJS application to be routed to the appropriate content. This can be done via Internet Information Services (IIS) Manager if you're using IIS, or by editing your web.config if you're using IIS or IIS Express. In your web.config, this means having a <rule> element under configuration > system.webServer > rewrite > rulesthat looks something like this:

<rule name="Rewrite requests back to the root of the app so AngularJS processes them" stopProcessing="true">
  <match url=".*" />
  <conditions>
    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
  </conditions>
  <action type="Rewrite" url="/" />
</rule>

This rule simply tells IIS to map any requests that aren't for a file that exists, or a directory that exists, back to the root of the application. Because the action specified is "Rewrite", the server responds to the requested URL with the content from "/", rather than returning an instruction to the browser (via an HTTP 301/302 redirect) to request the content from a different URI. If we didn't tell IIS to only redirect URIs that don't exist on disk, all the CSS, scripts, images, etc, that we request would also result in the markup of the AngularJS app being returned!

This isn't perfect - handling of addresses that don't exist in the AngularJS app needs work as these won't result in a "proper" 404 response being returned, but there are probably some tweaks that can be made to cater for this

About Rob

I've been interested in computing since the day my Dad purchased his first business PC (an Amstrad PC 1640 for anyone interested) which introduced me to MS-DOS batch programming and BASIC.

My skillset has matured somewhat since then, which you'll probably see from the posts here. You can read a bit more about me on the about page of the site, or check out some of the other posts on my areas of interest.

No Comments