I have just started evaluating the node-http-proxy because I need to have a scalable web socket server.
I have tested the ’simple-balancer-with-websockets’ example provided in the repository but it does not work when acting as a proxy to multiple addresses. It only works as a proxy for one address!
When proxying to multiple addresses a WebSocket hangup error as follows:
Error: socket hang up
at createHangUpError (http.js:1472:15)
at Socket.socketOnEnd [as onend] (http.js:1568:23)
at Socket.g (events.js:180:16)
at Socket.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:920:16
at process._tickCallback (node.js:415:13)
I am using:
node 0.10.26 socket io 1.0.6 node-http-proxy 1.1.5 platform OSX
The following is the load-balancer. Its only difference to the provided sample is the addresses used and the listen port.
var http = require('http'),
httpProxy = require('http-proxy');
//
// A simple round-robin load balancing strategy.
//
// First, list the servers you want to use in your rotation.
//
var addresses = [
{
host: 'localhost',
port: 8000
},
{
host: 'localhost',
port: 8001
},
{
host: 'localhost',
port: 8002
}
];
//
// Create a HttpProxy object for each target
//
var proxies = addresses.map(function (target) {
return new httpProxy.createProxyServer({
target: target
});
});
//
// Get the proxy at the front of the array, put it at the end and return it
// If you want a fancier balancer, put your code here
//
function nextProxy() {
var proxy = proxies.shift();
proxies.push(proxy);
return proxy;
}
//
// Get the 'next' proxy and send the http request
//
var server = http.createServer(function (req, res) {
nextProxy().web(req, res);
});
//
// Get the 'next' proxy and send the upgrade request
//
server.on('upgrade', function (req, socket, head) {
nextProxy().ws(req, socket, head);
});
server.listen(9000);
The basic http server acting as a target for the above load-balancer is:
var http = require('http'),
fs = require('fs'),
io = require('socket.io');
var args = process.argv.splice(2);
var port = args[0] || 8000;
server = http.createServer(function(req, res) {
var filePath = (__dirname + '/public/connect.html');
fs.readFile(filePath,function (err, data){
res.writeHead(200, {'Content-Type': 'text/html','Content-Length':data.length});
res.write(data);
res.end();
});
});
server.listen(port, function() {
console.log('ws listening on: ' + port);
});
io = io(server);
io.on('connect', function(socket){
console.log('socket connected');
socket.emit('message', 'ws message from ' + port);
});
The client html is:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
socket.on('message', function (data) {
console.log(data);
});
</script>
</head>
<body>
node-http-proxy basic load balance test with websockets
</body>
</html>
I regard this as a basic test and yet it does not work! Can anyone explain what I am doing wrong and suggest a solution please?
Many thanks for any thoughts.
Socket.io 1.0 needs sticky sessions. See socket.io/docs/using-multiple-nodes
First engine.io makes an xhr request then it makes an websocket request. Both requests need to reach the same socket.io server. Even more so if engine.io needs to fallback to long polling etc . . .
To fix it, you just need to make your proxy server session aware. It can still round robin fresh connections, but as soon as it serves a socket.io request it needs to route subsequent requests from that session to the same backend.