[iis] How do I configure IIS for URL Rewriting an AngularJS application in HTML5 mode?

I have the AngularJS seed project and I've added

$locationProvider.html5Mode(true).hashPrefix('!');

to the app.js file. I want to configure IIS 7 to route all requests to

http://localhost/app/index.html

so that this works for me. How do I do this?

Update:

I've just discovered, downloaded and installed the IIS URL Rewrite module, hoping this will make it easy and obvious to achieve my goal.

Update 2:

I guess this sums up what I'm trying to achieve (taken from the AngularJS Developer documentation):

Using this mode requires URL rewriting on server side, basically you have to rewrite all your links to entry point of your application (e.g. index.html)

Update 3:

I'm still working on this and I realise I need to NOT redirect (have rules that rewrite) certain URLs such as

http://localhost/app/lib/angular/angular.js
http://localhost/app/partials/partial1.html

so anything that is in the css, js, lib or partials directories isn't redirected. Everything else will need to be redirected to app/index.html

Anyone know how to achieve this easily without having to add a rule for every single file?

Update 4:

I have 2 inbound rules defined in the IIS URL Rewrite module. The first rule is:

IIS URL Rewrite Inbound Rule 1

The second rule is:

IIS URL Rewrite Inbound Rule 2

Now when I navigate to localhost/app/view1 it loads the page, however the supporting files (the ones in the css, js, lib and partials directories) are also being rewritten to the app/index.html page - so everything is coming back as the index.html page no matter what URL is used. I guess this means my first rule, that is supposed to prevent these URLs from being processed by the second rule, isn't working.. any ideas? ...anyone? ...I feel so alone... :-(

This question is related to iis url-rewriting angularjs

The answer is


The issue with only having these two conditions:

  <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
  <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />

is that they work only as long as the {REQUEST_FILENAME} exists physically on disk. This means that there can be scenarios where a request for an incorrectly named partial view would return the root page instead of a 404 which would cause angular to be loaded twice (and in certain scenarios it can cause a nasty infinite loop).

Thus, some safe "fallback" rules would be recommended to avoid these hard to troubleshoot issues:

  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.html$" negate="true" />
  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.js$" negate="true" />
  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.css$" negate="true" />

or a condition that matches any file ending:

<conditions>
  <!-- ... -->
  <add input="{REQUEST_FILENAME}" pattern=".*\.[\d\w]+$" negate="true" />
</conditions>

I've been trying to deploy a simple Angular 7 application, to an Azure Web App. Everything worked fine, until the point where you refreshed the page. Doing so, was presenting me with an 500 error - moved content. I've read both on the Angular docs and in around a good few forums, that I need to add a web.config file to my deployed solution and make sure the rewrite rule fallback to the index.html file. After hours of frustration and trial and error tests, I've found the error was quite simple: adding a tag around my file markup.


The easiest way I found is just to redirect the requests that trigger 404 to the client. This is done by adding an hashtag even when $locationProvider.html5Mode(true) is set.

This trick works for environments with more Web Application on the same Web Site and requiring URL integrity constraints (E.G. external authentication). Here is step by step how to do

index.html

Set the <base> element properly

<base href="@(Request.ApplicationPath + "/")">

web.config

First redirect 404 to a custom page, for example "Home/Error"

<system.web>
    <customErrors mode="On">
        <error statusCode="404" redirect="~/Home/Error" />
    </customErrors>
</system.web>

Home controller

Implement a simple ActionResult to "translate" input in a clientside route.

public ActionResult Error(string aspxerrorpath) {
    return this.Redirect("~/#/" + aspxerrorpath);
}

This is the simplest way.


It is possible (advisable?) to enhance the Error function with some improved logic to redirect 404 to client only when url is valid and let the 404 trigger normally when nothing will be found on client. Let's say you have these angular routes

.when("/", {
    templateUrl: "Base/Home",
    controller: "controllerHome"
})
.when("/New", {
    templateUrl: "Base/New",
    controller: "controllerNew"
})
.when("/Show/:title", {
    templateUrl: "Base/Show",
    controller: "controllerShow"
})

It makes sense to redirect URL to client only when it start with "/New" or "/Show/"

public ActionResult Error(string aspxerrorpath) {
    // get clientside route path
    string clientPath = aspxerrorpath.Substring(Request.ApplicationPath.Length);

    // create a set of valid clientside path
    string[] validPaths = { "/New", "/Show/" };

    // check if clientPath is valid and redirect properly
    foreach (string validPath in validPaths) {
        if (clientPath.StartsWith(validPath)) {
            return this.Redirect("~/#/" + clientPath);
        }
    }

    return new HttpNotFoundResult();
}

This is just an example of improved logic, of course every web application has different needs


I write out a rule in web.config after $locationProvider.html5Mode(true) is set in app.js.

Hope, helps someone out.

  <system.webServer>
    <rewrite>
      <rules>
        <rule name="AngularJS Routes" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>

In my index.html I added this to <head>

<base href="/">

Don't forget to install IIS URL Rewrite on server.

Also if you use Web API and IIS, this will work if your API is at www.yourdomain.com/api because of the third input (third line of condition).


I had a similar issue with Angular and IIS throwing a 404 status code on manual refresh and tried the most voted solution but that did not work for me. Also tried a bunch of other solutions having to deal with WebDAV and changing handlers and none worked.

Luckily I found this solution and it worked (took out parts I didn't need). So if none of the above works for you or even before trying them, try this and see if that fixes your angular deployment on iis issue.

Add the snippet to your webconfig in the root directory of your site. From my understanding, it removes the 404 status code from any inheritance (applicationhost.config, machine.config), then creates a 404 status code at the site level and redirects back to the home page as a custom 404 page.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404"/>
      <error statusCode="404" path="/index.html" responseMode="ExecuteURL"/>
    </httpErrors>
  </system.webServer>
</configuration>

In my case I kept getting a 403.14 after I had setup the correct rewrite rules. It turns out that I had a directory that was the same name as one of my URL routes. Once I removed the IsDirectory rewrite rule my routes worked correctly. Is there a case where removing the directory negation may cause problems? I can't think of any in my case. The only case I can think of is if you can browse a directory with your app.

<rule name="fixhtml5mode" stopProcessing="true">
  <match url=".*"/>
  <conditions logicalGrouping="MatchAll">
    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
  </conditions>
  <action type="Rewrite" url="/" />
</rule>

Examples related to iis

ASP.NET Core 1.0 on IIS error 502.5 CS1617: Invalid option ‘6’ for /langversion; must be ISO-1, ISO-2, 3, 4, 5 or Default Publish to IIS, setting Environment Variable IIS Manager in Windows 10 The page cannot be displayed because an internal server error has occurred on server The service cannot accept control messages at this time NuGet: 'X' already has a dependency defined for 'Y' Changing project port number in Visual Studio 2013 System.Data.SqlClient.SqlException: Login failed for user "This operation requires IIS integrated pipeline mode."

Examples related to url-rewriting

Apache 2.4 - Request exceeded the limit of 10 internal redirects due to probable configuration error Rewrite URL after redirecting 404 error htaccess How to change the URL from "localhost" to something else, on a local system using wampserver? .htaccess not working on localhost with XAMPP URL rewriting with PHP Rewrite all requests to index.php with nginx How do I configure IIS for URL Rewriting an AngularJS application in HTML5 mode? .htaccess rewrite subdomain to directory How to remove index.php from URLs? How to redirect a url in NGINX

Examples related to angularjs

AngularJs directive not updating another directive's scope ERROR in Cannot find module 'node-sass' CORS: credentials mode is 'include' CORS error :Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400 Print Html template in Angular 2 (ng-print in Angular 2) $http.get(...).success is not a function Angular 1.6.0: "Possibly unhandled rejection" error Find object by its property in array of objects with AngularJS way Error: Cannot invoke an expression whose type lacks a call signature