I need to create an application that proxies a request from port A to Port B.
For instance if a user connects on port 3000 he will be routed (under the hood) to port 3001, therefore the "original" application will run on port 3001 but in the client (browser) the user will put port 3000.
Not redirect...
http://example.com:3000/foo/bar
A new server will be created which listens to port 3001 and all the call are actually to port 3000 running with the new server and new port.
Since port 3000 is actually occupied,by my reverse proxy app? how should I test it...
Is there a way to test this to verify that this is working,e.g. by unit testing?
I've found this module https://github.com/nodejitsu/node-http-proxy which might be able to help.
Straight from the node-http-proxy docs, this is quite simple. You can test it simply by making an HTTP request to port 3000 -- if you get the same response as you do on port 3001, it's working:
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a proxy server with custom application logic
//
var proxy = httpProxy.createProxyServer({});
var server = http.createServer(function(req, res) {
// You can define here your custom logic to handle the request
// and then proxy the request.
proxy.web(req, res, {
// Your real Node app
target: 'http://127.0.0.1:3001'
});
});
console.log("proxy listening on port 3000")
server.listen(3000);
I highly recommend you write a suite of integration tests using some thing like mocha for your project as well - in this way, you can run your tests both against your server directly and against your proxy. If tests pass against both, then you can be assured your proxy is behaving as expected.
A unit test using mocha and should.js would look something like this:
var should = require('should');
describe('server', function() {
it('should respond', function(done) {
// ^ optional synchronous callback
request.get({
url: "http://locahost:3000"
// ^ Port of your proxy
}, function(e, r, body) {
if (e)
throw new Error(e);
body.result.should.equal("It works!");
done(); // call the optional synchronous callback
});
});
});
You then simply run your test (once Mocha is installed):
$ mocha path/to/your/test.js
You can either verify that this is working by adding the following
to the proxy request (as described in Remus answer )
proxy.on('proxyReq', function (proxyReq, req, res, options) {
res.setHeader('App-Proxy', 'proxy');
});
In this way you can verify that your "original" call is working against the new server proxy and even provide the ability to create a UT,in addition you can use the changeOrigin:true property...
Related
In my Vue.js app I'm using nightwatch to test my app. I have the following spec:
module.exports = {
'wrong email or password': function (browser) {
const devServer = browser.globals.devServerURL
var nock = require('nock');
var couchdb = nock('http://localhost:3000/')
.get('api/v1/login')
.reply(401, {
error: 'dupa'
});
browser
.url(devServer + '/login')
.setValue('input[type=email]', 'email#example.com')
.setValue('input[type=password]', 'password')
.click('.login')
.assert.containsText('#app', 'Niepoprawny email lub hasło.')
.end()
}
}
In my test I'm trying to use https://github.com/node-nock/nock. But unfortunately this not mocks any requests. What I'm doing wrong?
Nock replaces the HTTP mechanism in the browser environment in which it is run.
Since you're running it in your test, which isn't running in the browser, the browser environment is unchanged.
There are several things you could do, but that depends on what you're trying to achieve:
You could write a fake server and have it listen at port 3000 and answer any way you like.
You could configure your application to use a different mechanism according to configuration, and have it load a Nock 'strategy' in the test.
If you have other tests checking the UI, you could replace this test with unit tests and integration tests for the functions that do the actual requests.
To write a fake, you just need a simple server that returns the answer you want. Here's an example with express.js:
const express = require('express')
const app = express()
app.get('/api/v1/login', function (req, res) {
res.send('Some response')
})
app.listen(3000, function () {
console.log('server listening on port 3000')
})
I am new in Bluemix. So far I created web app,got its code and run this app in localhost. Everything works good. The app uses AngularJs and json-server. Later on I will Node.js too. To run it I use 'json-server --watch db.json'. The json file contains various json arrays and objects. And this is my list of links.
http://localhost:3000/news
http://localhost:3000/events
http://localhost:3000/city
http://localhost:3000/administration
http://localhost:3000/deputy_mayors
http://localhost:3000/alcazar_park
http://localhost:3000/feedback
My guess is that all those links should be changed to a live route instead of using localhost. In my dashboard I can see the name's app the route(theo-larissa.mybluemix.net) and it's state with is stopped. Now when I am trying to start the app,I get this message
404 Not Found: Requested route ('theo-larissa.mybluemix.net') does not exist.
Any ideas how to fix this?
Thanks in advance,
Theo.
What do your console logs for theo-larissa.mybluemix.net show? One of the really common deployment mistakes is to leave the port hard-coded in your application when you deploy it to Bluemix. You can't do that; you have to allow Bluemix to specify the port your application will use. You would do that, for example, by encoding something like the following when you create the server:
var server = app.listen(app.get('port'), function()
{console.log('Listening on port %d', server.address().port);});
If you wanted to make this fully automated, you could include code like the following:
app.set('port', appEnv.port);
app.set('appName', 'theo-larissa');
if (cfenv.getAppEnv().isLocal == true)
{http.createServer(app).listen(app.get('port'),
function(req, res) {console.log(app.get('appName')+' is listening locally on port: ' + app.get('port'));});
}
else
{
var server = app.listen(app.get('port'), function() {console.log('Listening on port %d', server.address().port);});
}
app.set('port', appEnv.port);
app.set('appName', 'theo-larissa');
if (cfenv.getAppEnv().isLocal == true)
{http.createServer(app).listen(app.get('port'),
function(req, res) {console.log(app.get('appName')+' is listening locally on port: ' + app.get('port'));});
}
else
{
var server = app.listen(app.get('port'), function() {console.log('Listening on port %d', server.address().port);});
}
I need to run multiple Node apps on the same port. I've found out that I can run multiple node apps using one port, thanks to this SO question Running multiple Node (Express) apps on same port But it's not working for me probably bec. I'm using Restify unless I did something wrong somewhere.
I already have "app1" running on this one port using PM2 built using Restify. I've made another app "app2". The paths are like these:
/var/www/app1
/var/www/app2
with each app having common routes like these:
app.get('/', func...);
app.get('/about', func...);
app.post('/foo', func...);
app.post('/bar', func...);
I've set up "app1"'s last lines of code as: exports.app = app instead of app.listen(8080, function() { ... });
and, where app is
var app = restify.createServer({
name: 'app1'
});
"app2" is the same as well...
My main.js file (which is saved in /var/www/) is also built on Restify:
main
.use('/app`', require('./app1/index').app)
.listen(8080);
where main is
var main = restify.createServer({
name: 'main'
});
But I'm getting an error such as this when I type node main.js (I haven't tried with PM2 yet):
/var/www/node_modules/restify/node_modules/assert-plus/assert.js:45
throw new assert.AssertionError({
^
AssertionError: handler (function) is required
at process (/var/www/node_modules/restify/lib/server.js:76:24)
at argumentsToChain (/var/www/node_modules/restify/lib/server.js:84:13)
at Server.use (/var/www/node_modules/restify/lib/server.js:625:6)
at Object.<anonymous> (/var/www/main.js:47:8)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
Note: I've turned off all the apps running under PM2. There are no node apps running on any port.
The only way to do this effectively is to run an HTTP proxy configured to answer requests on a single port and pass them, based upon URL patterns, to servers running on other ports, a simple example of which can be found at A HTTP Proxy Server in 20 Lines of node.js Code.
In essence, your publicly visible proxy server runs on port 80 and you run other servers to handle specific requests.
So for example, if you run three HTTP servers, one as a forwarding proxy and two for specific functions such that:
proxy on port 80
server2 on port 8080 for requests matching regexp:/^\/first(?:\/.*)?$/
server3 on port 8081 for requests matching regexp:/^\/second(?:\/.*)?$/
where the only server that has a public connection is your proxy.
When the proxy receives a request for /first or /first/index.html, it forwards the request to server2 which returns a result document that the proxy then sends back to the original requester.
When it receives a request for /second/foo/bar/page.html, it does the same but using server3 to produce a result.
http-proxy is an implementation of this strategy which uses the http-proxy-rules plugin to process and forward requests based on URL patterns.
UPDATE
For the purposes of clarity, we assume proxy, server2, and server3 above represent individual node HTTP server instances listening on a single IP address but separate ports on the same machine.
Example:
var http = require('http'),
httpProxy = require('http-proxy'),
HttpProxyRules = require('http-proxy-rules');
// Set up proxy rules instance
// where
// any request for /hostname/app1 will be proxy-ed via SERVER2
// any request for /hostname/app2 will be proxy-ed via SERVER3
var proxyRules = new HttpProxyRules({
rules: {
'.*/app1/': 'http://localhost:8080', // TO SERVER2
'.*/app2/': 'http://localhost:8081' // TO SERVER3
}
});
// Create reverse proxy instance
var proxy = httpProxy.createProxy();
// Create http server on hostname:80 that leverages reverse
// proxy instance and proxy rules to proxy requests to
// different one of two target servers
http.createServer(function(req, res) { // PROXY
// a match method is exposed on the proxy rules instance
// to test a request to see if it matches against one
// of the specified rules
var target = proxyRules.match(req);
if (target) {
return proxy.web(req, res, {
target: target
});
}
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('No rule found for this request');
}).listen(80);
// create a new HTTP server on localhost:8080 to process
// requests sent from the proxy
http.createServer(function (req, res) { // SERVER2
res.writeHead(200, { 'Content-Type': 'text/plain' });
var headers=JSON.stringify(req.headers,true,2);
res.write('request successfully proxy-ed to SERVER2!' + '\n' + headers);
res.end();
}).listen(8080,'localhost');
// create a new HTTP server on localhost:8081 to process
// requests sent from the proxy
http.createServer(function (req, res) { // SERVER3
res.writeHead(200, { 'Content-Type': 'text/plain' });
var headers=JSON.stringify(req.headers,true,2);
res.write('request successfully proxy-ed to SERVER3!' + '\n' + headers);
res.end();
}).listen(8081,'localhost');
Using this setup:
only the proxy server will be available externally on port 80
the servers running on ports 8080 & 8081 are only available on the local machine
requests received on the proxy at hostname:80 that match the /app1 path (and descendants) will be proxy-ed by the server running on localhost:8080
requests received on the proxy at hostname:80 that match the /app2 path (and descendants) will be served by the server running on localhost:8081
A scenario of mine:
I'd like to convert jsx file (React) into normal js.
And I need browserify or a kind because one of modules needs require.
Watching files for every modifications and repeating tasks make me feel overkill. Those tasks are only needed to be executed on timing of browser reload (on a request).
I know Rails development env does this, but in this case a node.js app.
So I do like to use a http proxy in front of my app and let execute those tasks before my app responses to browser.
Any tools available already? or any advice for implementing such a proxy?
I don't mind if those tools are available already in any language, (node.js, python or ruby), but if non I'd like to implement one with node.js.
While app server is running on port 3000, I wrote a quick and dirty reverse proxy like this.
This proxy listens on port 31000 and just forward every requests, but if path is "/bundle.js" execute a command before forward the request.
var exec = require('child_process').exec;
var http = require('http');
var httpProxy = require('http-proxy')
var proxy = httpProxy.createProxyServer({target: "http://localhost:3000"})
var proxyServer = http.createServer(function(req, res) {
if (req.url == '/bundle.js') {
exec("jsx src/ build/ && browserify build/app.js -o bundle.js", function(err, stdout, stderr) {
if (err) {
console.error('error: ' + err);
}
proxy.web(req, res);
});
} else {
proxy.web(req, res);
}
});
proxyServer.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
proxyServer.listen(3100);
I'm quite new to Node.js / Express, and I'm using it as a backend for an AngularJS app. I've looked all over StackOverflow for some help on my problem, but I can't seem to figure out how to port the suggestions to my code.
My application works as follows:
A long running Scala process periodically sends my Node.js application log messages. It does this by posting to an HTTP API
When the post is received, my application writes the log message to MongoDB
The log messages are then sent in real time to the Angular client.
I am having a problem with Node's modules, as I can't figure out how to refer to the socket instance in the Express controller.
As you can see, in server.js, socket.io is instantiated there. However, I would like the controller itself, logs.js, to be able to emit using the socket.io instance.
How can I refer to io in the controller? I'm not sure how to pass the io instance to the controller so I can emit messages?
Here is some of the Node code:
server.js
var app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);
require('./lib/config/express')(app);
require('./lib/routes')(app);
server.listen(config.port, config.ip, function() {
console.log('Express server listening on %s:%d, in %s mode', config.ip, config.port, app.get('env'));
});
io.set('log level', 1); // reduce logging
io.sockets.on('connection', function(socket) {
console.log('socket connected');
socket.emit('message', {
message: 'You are connected to the backend through the socket!'
});
});
exports = module.exports = app;
routes.js
var logs = require('./controllers/logs'),
middleware = require('./middleware');
module.exports = function(app) {
app.route('/logs')
.post(logs.create);
}
logs.js
exports.create = function(req, res) {
// write body of api request to mongodb (this is fine)
// emit log message to angular with socket.io (how do i refer to the io instance in server.js)
};
You can use a pattern based on standard JS closures. The main export in logs.js will not be the controller function itself, but a factory function that will accept all needed dependencies, and create the controller:
exports.create = function(socket) {
return function(req, res) {
// write body of api request to mongodb
socket.emit();
}
}
Then, when you want to use it:
app.route('/logs').post(logs.create(socket));
Since you set up your routes in a separate package, you have to use the same pattern in routes.js - routes should receive the socket to use as a parameter.
This pattern works well if you want to handle those things with DI later, or test your controllers with mock "sockets".