好吧,我已经花了一个多星期的时间试图弄清楚这一点,但无济于事,所以如果有人有线索,你就是英雄。这不是一个容易回答的问题,除非我是个笨蛋。
我正在使用 node-http-proxy 将粘性会话代理到在不同端口上运行的 16 个 node.js 工作人员。
我使用 Socket.IO 的 Web Sockets 来处理一堆不同类型的请求,也使用传统的请求。
当我通过 node-http-proxy 将服务器切换到代理时,有时会出现一个新问题,我的 Socket.IO 会话无法建立连接。
我真的无法在我的一生中稳定地复制它,唯一的方法是将它从多个客户端抛出大量流量到服务器。
如果我重新加载用户的浏览器,它有时可以重新连接,有时不能。
粘性会话
我必须代理粘性会话,因为我的应用程序基于每个工作人员进行身份验证,因此它根据其 Connect.SID cookie 路由请求(我正在使用 connect/express)。
好的,一些代码
这是我的 proxy.js 文件,它在节点中运行并路由到每个工作人员:
var http = require('http');
var httpProxy = require('http-proxy');
// What ports the proxy is routing to.
var data = {
proxyPort: 8888,
currentPort: 8850,
portStart: 8850,
portEnd: 8865,
};
// Just gives the next port number.
nextPort = function() {
var next = data.currentPort++;
next = (next > data.portEnd) ? data.portStart : next;
data.currentPort = next;
return data.currentPort;
};
// A hash of Connect.SIDs for sticky sessions.
data.routes = {}
var svr = httpProxy.createServer(function (req, res, proxy) {
var port = false;
// parseCookies is just a little function
// that... parses cookies.
var cookies = parseCookies(req);
// If there is an SID passed from the browser.
if (cookies['connect.sid'] !== undefined) {
var ip = req.connection.remoteAddress;
if (data.routes[cookies['connect.sid']] !== undefined) {
// If there is already a route assigned to this SID,
// make that route's port the assigned port.
port = data.routes[cookies['connect.sid']].port;
} else {
// If there isn't a route for this SID,
// create the route object and log its
// assigned port.
port = data.currentPort;
data.routes[cookies['connect.sid']] = {
port: port,
}
nextPort();
}
} else {
// Otherwise assign a random port, it will/
// pick up a connect SID on the next go.
// This doesn't really happen.
port = nextPort();
}
// Now that we have the chosen port,
// proxy the request.
proxy.proxyRequest(req, res, {
host: '127.0.0.1',
port: port
});
}).listen(data.proxyPort);
// Now we handle WebSocket requests.
// Basically, I feed off of the above route
// logic and try to route my WebSocket to the
// same server regular requests are going to.
svr.on('upgrade', function (req, socket, head) {
var cookies = parseCookies(req);
var port = false;
// Make sure there is a Connect.SID,
if (cookies['connect.sid'] != undefined) {
// Make sure there is a route...
if (data.routes[cookies['connect.sid']] !== undefined) {
// Assign the appropriate port.
port = data.routes[cookies['connect.sid']].port;
} else {
// this has never, ever happened, i've been logging it.
}
} else {
// this has never, ever happened, i've been logging it.
};
if (port === false) {
// this has never happened...
};
// So now route the WebSocket to the same port
// as the regular requests are getting.
svr.proxy.proxyWebSocketRequest(req, socket, head, {
host: 'localhost',
port: port
});
});
客户端/现象
套接字连接如下:
var socket = io.connect('http://whatever:8888');
登录大约 10 秒后,我在此侦听器上收到此错误,这并没有多大帮助。
socket.on('error', function (data) {
// this is what gets triggered. ->
// Firefox can't establish a connection to the server at ws://whatever:8888/socket.io/1/websocket/Nnx08nYaZkLY2N479KX0.
});
浏览器发送的 Socket.IO GET 请求永远不会回来 - 它只是挂起等待,即使在错误回来之后,所以它看起来像一个超时错误。服务器从不响应。
服务器端 - 工作人员
这就是工作人员接收套接字请求的方式。很简单。所有工人都有相同的代码,所以你认为他们中的一个会收到请求并确认它......
app.sio.socketio.sockets.on('connection', function (socket) {
// works... some of the time! all of my workers run this
// exact same process.
});
概括
这是很多数据,我怀疑是否有人愿意面对它,但我完全被难住了,不知道接下来在哪里检查,下一步记录,无论如何,要解决它。我已经尝试了我所知道的一切以查看问题所在,但无济于事。
更新
好的,我相当确定问题出在node-http-proxy github 主页上的以下声明中:
node-http-proxy 与 <= 0.8.x 兼容,如果您正在寻找 >= 0.10 兼容版本,请查看 caronte
我正在运行 Node.js v0.10.13,这种现象与一些人在 github 问题上对此主题的评论完全相同:它只是随机丢弃 websocket 连接。
我已经尝试实现 caronte,即“较新”的分支,但它根本没有记录,我已经尽我最大的努力将他们的文档拼凑成一个可行的解决方案,但我无法让它转发 websockets,我的 Socket。 IO 降级为轮询。
关于如何实现和工作还有其他想法吗?node-http-proxy 昨天有 8200 次下载!肯定有人在使用今年的 Node 版本并代理 websockets....
我到底在寻找什么
我想完成一个代理服务器(最好是 Node),它代理多个 node.js 工作人员,并通过基于浏览器 cookie 的粘性会话路由请求。该代理需要稳定地支持传统请求以及 Web 套接字。
或者...
如果可行,我不介意通过集群节点工作人员完成上述任务。我唯一真正的要求是根据请求标头中的 cookie 维护粘性会话。
如果有比我正在尝试的更好的方法来完成上述工作,我完全赞成。