1

I have an AngularJS app built on top of Node.JS that is hosted in Azure (IIS) and uses HTML5 mode. In situations where I don't use Node.JS and just use AngularJS with IIS I can rewrite URLs so that a page refresh doesn't cause a 404 error using the following rule in the IIS Web.config:

<rule name="AngularJSHTML5Mode" 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>

However, when using Angular on top of Node.js (with ExpressJS) I get an error such as "Cannot GET /myroute" on page refresh, even with the above rule in IIS. Is there something I need to configure in Server.js or a different rule in Web.config.

Here is what I have in Express at the moment. I am using Express 4:

// Initialize Express App
var app = express();

var listener = app.listen(1337, function () {
    console.log('Listening on port ' + listener.address().port); //Listening on port 1337
});

app.use(express.static(__dirname + "/public"));

I understand that page refreshes shouldn't happen in a SPA as a matter of practice, but they do, and I need to account for this.

3
  • 3
    No, you have to configure it within node.js. Once the request is handed off to node.js, web.config does nothing. Commented Sep 11, 2015 at 18:31
  • Do you have an example of how to do that? Commented Sep 11, 2015 at 18:40
  • 1
    I do not, but it's usually just a simple app.get( middleware that goes after your routes and renders index.html instead of giving a 404. Commented Sep 11, 2015 at 18:41

2 Answers 2

2

I've experimented and this is what has worked for me:

web.config (site.js is the entry point to my node app)

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpErrors existingResponse="PassThrough" />

        <iisnode nodeProcessCommandLine="&quot;c:\program files\nodejs\node.exe&quot;" watchedFiles="*.js" 
      interceptor="&quot;%programfiles%\iisnode\interceptor.js&quot;" promoteServerVars="LOGON_USER"/>
        <handlers>
            <add name="iisnode" path="site.js" verb="*" modules="iisnode" />
        </handlers>

        <rewrite>
            <rules>
                <clear />
                <rule name="default">
                    <match url="/*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
                    <action type="Rewrite" url="site.js" />
                </rule>
            </rules>
        </rewrite>

        <security>
            <requestFiltering>
                <hiddenSegments>
                    <add segment="node_modules" />
                </hiddenSegments>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>

static file server in express + url rewrite

app.use(express.static(clientDir));

// for SPA
app.get('/*', function(req,res, next){
    res.format({
        html: function(){
            res.sendFile(path.join(clientDir, 'index.html'));
        },
        json: function(){
            next();
        }
    });
});

//routes...

I have also tried to implement url rewrite with virtual app in iis. This doesn't work. Instead, I had to configure a path within my node module to strip the leading part of the route.

However, you can have iis serve the static files once your app has bootstrapped.

Sign up to request clarification or add additional context in comments.

3 Comments

I tried this but it didn't work for me. I am using Express 4 and will post the appropriate code in my original post.
@Kode this absolutely works for me. I have an example here: github.com/futurechan/how-to-node/tree/master/leveraging-gulp It doesn't include the web.config, but I can deploy that to iis via iisnode and include the web.config above, and it works.
Thanks, I just got it working via another method. Posting the answer now.
0

Upon further digging, I didn't need the Web config. I have this in my server.js to institute the connection to the Angular index file:

var app = express();

app.use(express.static(__dirname + "/public"));


var listener = app.listen(1337, function () {
    console.log('Listening on port ' + listener.address().port); //Listening on port 1337
});

This part is critical, at the end of all your GETs, POSTs, etc. I added this as the last function. It needs to be last since it is a catch all and if you put it before a GET or POST function it won't see it as Express but a broken Angular route, and if your App.js is configured correctly, will route to the homepage (not desired):

// Placed at end for routing non-Express calls/AngularJS refreshes
app.use('/*', function (req, res) {
    res.sendFile(__dirname + '/public/index.html');
});

1 Comment

It doesn't actually need to be last. You can leverage content negotiation. Requests for text/html will go to the static files, if a match isn't found, you serve the index.html. Requests for application/json can go to routes regardless of order.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.