Understanding vhost in Express Node.js - javascript

I am trying to understand how vhost actually works in Express JS. Here's a working code sample (forgot where I pulled this from):
// -- inside index.js --
var EXPRESS = require('express');
var app = EXPRESS.createServer();
app.use(EXPRESS.vhost('dev.example.com', require('./dev').app));
app.listen(8080);
// -- inside dev.js --
var EXPRESS = require('express');
var app = exports.app = EXPRESS.createServer();
app.get('/', function(req, res)
{
// Handle request...
});
Now, my question is, why do we call createServer() twice? Why does this even work? Is vhost internally "merging" the two servers together?

Node.js is event-driven, and when a request comes in, the request event is raised on a http.Server. So basically, express.vhost (or really, connect.vhost) is a middleware function which raises the request event on another instance of a http.Server:
function vhost(req, res, next){
if (!req.headers.host) return next();
var host = req.headers.host.split(':')[0];
if (req.subdomains = regexp.exec(host)) {
req.subdomains = req.subdomains[0].split('.').slice(0, -1);
server.emit('request', req, res);
} else {
next();
}
};

Related

express-subdomain handling any subdomain

I'm trying to use https://github.com/bmullan91/express-subdomain for subdomain routing in express. The following are the contents of my main.js and src/routes/site files.
const express = require('express');
const bodyParser = require('body-parser');
const subdomain = require('express-subdomain');
const siteRouter = require('./src/routes/site');
const app = express()
app.use(express.json() );
app.use(express.urlencoded());
app.use(express.static('public'));
app.use(subdomain('*.www', siteRouter));
app.get('/', function(req, res) {
res.send('Homepage');
});
const server = app.listen(80,'x3.loc', function () {
var host = server.address().address;
var port = server.address().port;
console.log('X3 listening at http://%s:%s', host, port);
});
const express = require('express');
let router = express.Router();
router.get('/', function(req, res) {
res.send('Welcome to site');
});
module.exports = router;
This way of doing app.use(subdomain('*.www', siteRouter)); has been suggested in https://github.com/bmullan91/express-subdomain/issues/33 but does not work.
I have also tried just * as the subdomain aswell, but that caused the homepage w/o a subdomain, to get treated like one aswell. How could I get this to work?
We know that / matches any base path regardless of subdomain. So I made your homepage middleware "subdomain-aware" like so:
app.get('/', function(req, res,next) {
/* If there are any subdomains, skip to next handler, since request is not for the main home page */
if (req.subdomains.length > 0) {
return next();
}
res.send('Homepage');
});
Then I placed the middleware for subdomains below the homepage middleware like so:
app.use(subdomain('*', siteRouter));
This makes homepage middleware to serve requests for x3.loc and the subdomain middleware to serve requests for any subdomain like api.x3.loc or api.v1.x3.loc.
But in my opinion, the real fix should be done in the module. I think it should be changed so that either the case where req.subdomains being empty is handled, or * is matched against an actual string, instead of skipping the iteration.
I am surprised that the fix suggested in bug 33 worked as-is for the reporter. In my testing, it works the opposite way i.e. www.example.com goes to subdomain middleware while stat1.example.com goes to the homepage middleware. Perhaps the reporter saw this and swapped the middleware bodies.

express-subdomain not redirecting subdomain.localhost get request

I am using an express.js package called express-subdomain to facilitate requests to defined subdomains I set up.
As far as I understand, the subdomain constructor function expects an express router object which I pass to it from an exported router module.
What I have tried is as follows:
MAIN APP.JS SERVER FILE
var common = {
express: require('express'),
subdomain: require('express-subdomain')
};
common.app = common.express();
module.exports = common;
common.app.listen(3000, function () {
console.log(('app listening on http://localhost:3000'));
});
var router = require('./router/index');
// Error Handling
common.app.use(function(err, req, res, next) {
res.status(err.status || 500);
});
router/index
module.exports = function (){
var common = require('../app');
var router = common.express.Router();
common.app.get('/', function(req, res) {
res.send('Homepage');
});
common.app.use('/signup', require('./routes/signup'));
common.app.use(common.subdomain('login', require('./routes/login')));
}();
routes/login
var express = require('express');
var router = express.Router();
router.get('/', function (req, res) {
res.send('login working');
});
router.get('/info', function (req, res) {
});
module.exports = router;
I have tried to access the login subdomain at the following urls:
http://login.localhost
http://login.localhost:3000
http://login.localhost.com
http://login.localhost.com:3000
Any clarification or assistance appreciated.
author of express-subdomain here 👋
A couple of things:
Hosts must be setup correctly - I'd recommend something like so in your /etc/hosts file.
127.0.0.1 myapp.local
127.0.0.1 login.myapp.local
For more information on this see https://github.com/bmullan91/express-subdomain#developing-locally
Register the subdomain routes before any others, including the homepage route. The order is very important
The pattern you're using in /routes/index.js is not advised (requiring a self invoking function). Exporting the Router like you done in /routes/login.js is cleaner.
Finally, If you're still stuck take a look at the source for express subdomain and in particular its tests.
Happy coding.

request.url Express and Node

Im a newbie on node.js, I just wanted to know how to extract the requested url in this code
app.use(express.static(__dirname+"/public"));
Thank you for your help
As you can see on the static middleware source, a middleware is basic a function that receives the parameters (request, response, next_function).
So you could create a function that reads the url before it goes to static middleware.
var express = require('express');
var app = express();
var staticfn = express.static(__dirname+'/public');
app.use(function (req,res,next) {
console.log(req.url);
var sendStream = staticfn(req,res,next);
console.log(sendStream.path);
});
app.listen(3000)
As you can see on the send package used by the static middleware, the send function returns a object called SendStream.

How to write a node express app that serves most local files, but reroutes some to another domain?

I'm working on a small webapp that normally is built with a relatively complex process and then deployed to WebLogic.
However, the portion I'm working on is using AngularJS, and is all HTML and Javascript. It normally makes ajax calls into another webapp on the same domain. To shorten my development cycle, I'd like to avoid a build process and just reload the browser page.
I think I can do this with "node express", but the details escape me. I've managed to define a very simple app that just serves local files, but now I have to figure out how to detect some of those paths as matching an expression, and reroute those requests to a request to an external domain.
So, if it gets a request for "/diag/stuff.html", "/foo/thing.html", or just "/index.html", it will send back the file matching the same path. However, if the path matches "/fooService/.*", then I have to send back the response from a GET to the same path, but on a different host and port.
This is my trivial app so far:
var express = require('express');
var app = express();
app.use("/", express.static(__dirname));
app.listen(8000);
Update:
I like the proxy idea, so I did a local install of "http-proxy" (I forgot and first did a global install) then changed the script to this:
var express = require('express');
var app = express();
var httpProxy = require('http-proxy');
var proxy = new httpProxy.RoutingProxy();
app.use("/", express.static(__dirname));
app.get('/FooService/*', function(req, res) {
"use strict";
return proxy.proxyRequest(req, res, {
host: "foohost.net",
port: 80
});
});
app.listen(8000);
This fails with:
<path>\server.js:4
var proxy = new httpProxy.RoutingProxy();
^
TypeError: undefined is not a function
at Object.<anonymous> (<path>\server.js:4:13)
What might be wrong here?
Update:
Would it be useful to see the contents of "console.log(httpProxy)" after that "require"?:
function ProxyServer(options) {
EE3.call(this);
this.web = this.proxyRequest = createRightProxy('web')(options);
this.ws = this.proxyWebsocketRequest = createRightProxy('ws')(options);
this.options = options;
this.webPasses = Object.keys(web).map(function(pass) {
return web[pass];
});
this.wsPasses = Object.keys(ws).map(function(pass) {
return ws[pass];
});
this.on('error', this.onError.bind(this));
}
Does that provide a clue for why "new httpProxy.RoutingProxy()" says it's undefined?
You can use http-proxy and forward requests to different host. To install http-proxy you need to run sudo npm install http-proxy. Code that will handle proxy will look like that:
httpProxy = require('http-proxy');
proxy = new httpProxy.RoutingProxy();
(...)
app.get('/fooService/*', function (request, response) {
"use strict";
return proxy.proxyRequest(request, response, {
host : externalHost,
port : 80
});
});
UPDATE
Above code is working for http-proxy ~0.10.x. Since then lot of things had changed in library. Below you can find example for new version (at time of writing ~1.0.2):
var httpProxy = require('http-proxy'),
proxy = httpProxy.createProxyServer({});
(...)
app.get('/fooService/*', function (request, response) {
"use strict";
return proxy.web(request, response, {
target: 'http://fooservice.com'
});
});
If redirects meet your need, then that's the easiest solution:
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.use(app.router);
app.get('/fooService/*', function(req, res){
res.redirect(302, 'http://otherdomain.com:2222' + req.path);
});
app.listen(8000);
Note that it's generally considered good practice to use a subdirectory for your static files (like public above). Otherwise you could view your app file itself and anything else you keep in your application root!

How to mount app.get() routes on a particular path prefix

I'm writing an API using Node.js and Express. My API has GET methods of the form:
/api/v1/doSomething
/api/v1/doSomethingElse
My code is looking something like this:
server.js:
var app = express();
...
var routes = require('./routes')
routes.attachHandlers(app, '/api/v1')
routes/index.js
...
module.exports.attachHandlers = function(app, context) {
//get a list of all the other .js files in routes
//for each route, require() it and call it myRoute
myRoute.attachHandlers(app, context)
}
routes/some-route.js
...
module.exports.attachHandlers = function(app, context) {
app.get(context + '/doSomething', doSomething)
app.get(context + '/doSomethingElse', doSomethingElse)
}
...
Effectively I'm passing the context path/mount point down through the app. If somebody were to write a route like the following, though, the context would be lost:
app.get('/doFoo', foo)
Rather than having that part of the API mounted on /api/v1/doFoo it's on /doFoo. I would like to avoid having to pass the context path around like this.
app.use supports mounting middleware on an optional mount path. I have seen references online to mounting an entire Express application on a mount path using app.use. This seems like the sort of thing I want to do, but I'm not sure how to do it or if it's the best solution for my particular use case.
To summarise - I want to mount my app.get() routes with a particular prefix by default. What's the best way of doing this?
With Express 4.0, the task is much cleaner with the Router. You can create as many routers as you need to nicely partition your app, and then attached them with app.use(). For example:
myapp.js
var express = require("express"),
router = express.Router(),
app = express(),
port = 4000;
// Here we declare our API which will be visible under prefix path
router.get('/', function (req, res) {
console.log("request to subspace hello");
res.send({ message: "Hi from subspace /api/v1/"});
});
// we attach our routes under /api/v1
app.use('/api/v1', router);
// here we have direct, root-level routing
app.get('/', function (req, res) {
console.log("request to rootspace hello");
res.send({message: "Hi from root /"});
});
app.listen(port);
console.log("App active on localhost:" + port);
Then run
node myapp.js
and visit
http://localhost:4000 and http://localhost:4000/api/v1
Here's a working example of mounting a route in Express 3:
./snipe3app.js
var express = require('express');
var app = module.exports = express();
app.get('/subapp', function (req, res) {
res.send('You are on the /sub/subapp page.');
});
./app.js
var express = require('express'),
http = require('http'),
subApp = require('./snipe3app'),
app = express();
app.use(express.favicon());
app.use(express.bodyParser());
app.use(app.router);
app.use('/sub', subApp);
app.get('/', function (req, res) {
res.send('You are on the root page');
});
http.createServer(app).listen(3000, function(){
console.log('Express server listening on port 3000. Point browser to route /secure');
});
You have to pay attention to the order in which the routes are handled when doing this.
I think express-namespace will work for this.

Categories