In my last post I introduced the iisnode project which allows hosting node.js applications in IIS on Windows. In this article I discuss using URL rewriting with node.js apps hosted in IIS, functionality necessary in all but the most trivial IIS hosted node.js applications.
The problem
Consider the hello world sample code, saved in the hello.js file in IIS virtual directory:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello, world! [helloworld sample]');
}).listen(process.env.PORT);
along with the following web.config that registers the iisnode module as a handler of the hello.js file, therefore indicating it is a node.js application:
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="hello.js" verb="*" modules="iisnode" />
</handlers>
</system.webServer>
</configuration>
When both hello.js and web.config above are saved in the ‘node’ virtual directory in IIS, one can navigate to the node.js application using the following URL:
http://localhost/node/hello.js
As expected, IIS will realize the hello.js file maps to the iisnode handler and invoke it, and as expected a few million CPU cycles later a ‘Hello, world’ is sent back to the client.
However, when a subordinate URL path is requested, IIS returns an error, e.g:
The reason for this is that IIS does not understand that paths subordinate to the ‘hello.js’ component of the path should all be handled by the hello.js application. This is unacceptable for all but the most simplistic node.js applications, which typically own the entire URL space. Fortunately, it is easily remedied with the URL rewriting module.
URL rewriting module to the rescue
Fixing this problem requires configuring the URL rewriting module to indicate that the section of the request path that is subordinate to the hello.js component should be handled by the handler for the hello.js component itself. From IIS perspective the request processing occurs as if the request was made for http://localhost/node/helloworld/hello.js, but the original URL path is preserved and available for the handler to act on. URL rewriting is specified in the web.config file as follows (lines 17-24):
1: <configuration>
2: <system.webServer>
3: <!-- indicates that the hello.js file is a node.js application
4: to be handled by the iisnode module -->
5: <handlers>
6: <add name="iisnode" path="hello.js" verb="*" modules="iisnode" />
7: </handlers>
8: <!-- use URL rewriting to redirect the entire branch of the URL namespace
9: to hello.js node.js application; for example, the following URLs will
10: all be handled by hello.js:
11:
12: http://localhost/node/urlrewrite/hello
13: http://localhost/node/urlrewrite/hello/foo
14: http://localhost/node/urlrewrite/hello/foo/bar/baz?param=bat
15:
16: -->
17: <rewrite>
18: <rules>
19: <rule name="hello">
20: <match url="hello/*" />
21: <action type="Rewrite" url="hello.js" />
22: </rule>
23: </rules>
24: </rewrite>
25: </system.webServer>
26: </configuration>
The configuration above will not only cause all URLs subordinate to hello.js to handled by hello.js node application; it also allows the hello.js file name to be completely removed from the URL path. With the configuration above the node.js service can now be accessed using any of the following URLs:
http://localhost/node/hello/foo/bar/baz
http://localhost/node/hello/1/2/3
http://localhost/node/hello/f/b/b?param=bat
...
What request URL does the node.js application see?
The request URL passed by IIS to the node.js application is the original URL from before re-writing. For example:
Where do I get iisnode again?
Everything you need to get started is at https://github.com/tjanczuk/iisnode. Make sure to check out the urlrewrite sample. Feedback welcome!

This is pretty cool. Since NodeJS is living in IIS, do we get Windows Authentication for free?
ReplyDeleteYes, you will get windows authentication as well as all the other IIS modules for free.
ReplyDeleteThis is awesome. Thanks for the information. I ended up having to search for the url rewrite module for IIS on Windows 7, download and install it. Good bye to using ubuntu and a vm :)
ReplyDeleteI've got a question relating to URL Rewrite.
ReplyDeleteRight now my nodejs program handles URL in the form:
http://localhost/index
Where "/index" is what my .js program sees as the "pathname", using the built-in url.parse() function. All functions are called from a single .js file.
How would I set up URL Rewrite to simulate this? I would like my .js file to handle everything coming in on this machine. I don't want it to receive "/node/urlrewrite/etc/pararm
I'm sure this is an easy URL Rewrite exercise, but I'm new to it.
Thanks!
I have a question? Can you provide an iisnode JavaScript code example to get the windows user name from an authenticated user - assuming I have IIS set for windows authentication only.
ReplyDeletethank you
There is currently (v0.1.9) no way to extract the name of the Windows authenticated user from a node.js application running in iisnode. I've added https://github.com/tjanczuk/iisnode/issues/87 to address this issue.
ReplyDeleteTomasz, tell me please how context collected by modules through the pipeline is going to be passed to iisnode?
ReplyDeleteI see now huge problem with using Authentication and Authorization modules as well as with other which write something into context...