Is it possible to set a base URL for NodeJS app?


Question

I want to be able to host multiple NodeJS apps under the same domain, without using sub-domains (like google.com/reader instead of images.google.com). The problem is that I'm always typing the first part of the url e.g. "/reader" in Express/NodeJS.

How can I set up an Express app so that the base URL is something.com/myapp?

So instead of:

app.get("/myapp", function (req, res) {
   // can be accessed from something.com/myapp
});

I can do:

// Some set-up
app.base = "/myapp"

app.get("/", function (req, res) {
   // can still be accessed from something.com/myapp
});

I'd also like to configure Connect's staticProvider to behave the same way (right now it defaults to serving static files to something.com/js or something.com/css instead of something.com/myapp/js)

1
58
12/7/2010 10:20:20 AM

Accepted Answer

At the moment this is not supported, and it's not easy to add it on your own.

The whole routing stuff is buried deep inside the server code, and as a bonus there's no exposure of the routes them selfs.

I dug through the source and also checked out the latest version of Express and the Connect middleware, but there's still no support for such functionality, you should open a issue either on Connect or Express itself.

Meanwhile...

Patch the thing yourself, here's a quick and easy way with only one line of code changed.

In ~/.local/lib/node/.npm/express/1.0.0/package/lib/express/servers.js, search for:

// Generate the route
this.routes[method](path, fn);

This should be around line 357, replace that with:

// Generate the route
this.routes[method](((self.settings.base || '') + path), fn);

Now just add the setting:

app.set('base', '/myapp');

This works fine with paths that are plain strings, for RegEx support you will have to hack around in the router middleware yourself, better file an issue in that case.

As far as the static provider goes, just add in /mypapp when setting it up.

Update

Made it work with RegExp too:

// replace
this.routes[method](baseRoute(self.settings.base || '', path), fn);

// helper
function baseRoute(base, path) {
    if (path instanceof RegExp) {
        var exp = RegExp(path).toString().slice(1, -1);
        return new RegExp(exp[0] === '^' ? '^' + base + exp.substring(1) : base + exp);

    } else {
        return (base || '') + path;
    }
}

I only tested this with a handful of expressions, so this isn't 100% tested but in theory it should work.

Update 2

Filed an issue with the patch:
https://github.com/visionmedia/express/issues/issue/478

16
12/7/2010 12:14:42 PM

The express router can handle this since 4.0

http://expressjs.com/en/api.html#router

http://bulkan-evcimen.com/using_express_router_instead_of_express_namespace.html

var express = require('express');
var app = express();
var router = express.Router();

// simple logger for this router's requests
// all requests to this router will first hit this middleware
router.use(function(req, res, next) {
  console.log('%s %s %s', req.method, req.url, req.path);
  next();
});

// this will only be invoked if the path ends in /bar
router.use('/bar', function(req, res, next) {
  // ... maybe some additional /bar logging ...
  next();
});

// always invoked
router.use(function(req, res, next) {
  res.send('Hello World');
});

app.use('/foo', router);

app.listen(3000);

Previous answer (before express 4.0) :

The express-namespace module (dead now) used to do the trick :

https://github.com/visionmedia/express-namespace

require('express-namespace');

app.namespace('/myapp', function() {
        app.get('/', function (req, res) {
           // can be accessed from something.com/myapp
        });
});

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon