Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

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.

share|improve this question
3  
No, you have to configure it within node.js. Once the request is handed off to node.js, web.config does nothing. – Kevin B Sep 11 '15 at 18:31
    
Do you have an example of how to do that? – Kode Sep 11 '15 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. – Kevin B Sep 11 '15 at 18:41

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.

share|improve this answer
    
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 Sep 23 '15 at 13:47
1  
@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. – Josh C. Sep 23 '15 at 15:05
    
Thanks, I just got it working via another method. Posting the answer now. – Kode Sep 23 '15 at 15:06

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');
});
share|improve this answer
1  
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. – Josh C. Sep 23 '15 at 15:28

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.