Node.js http代理删除websocket请求
Node.js http-proxy drops websocket requests
好吧,我花了一个多星期的时间试图弄清楚这一点,但没有成功,所以如果有人知道,你就是英雄。这不是一个容易回答的问题,除非我是个傻瓜。
我使用nodehttp代理将粘性会话代理到在不同端口上运行的16个node.js工作程序。
我使用Socket.IO的Web套接字来处理一堆不同类型的请求,也使用传统的请求。
当我将服务器切换到通过节点http代理进行代理时,出现了一个新问题,有时我的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.
});
摘要
这是一大堆数据,我怀疑是否有人愿意面对它,但我完全被难住了,不知道下一步该在哪里检查,下一步要登录,不管怎样,来解决它。我已经尽了我所能来看看问题是什么,但都无济于事。
更新
好吧,我很确定问题出在节点http代理github主页上的这句话中:
节点http代理<=0.8.x兼容,如果您正在寻找>=0.10兼容版本请检查caronte
我正在运行Node.js v0.10.13,这种现象正如一些人在github问题中对此主题所评论的那样:它只是随机丢弃websocket连接。
我曾尝试实现caronte,这是一个"较新"的分叉,但它根本没有文档记录,我尽了最大努力将他们的文档拼凑成一个可行的解决方案,但我无法让它转发websocket,我的Socket.IO降级为轮询。
关于如何实施和发挥作用,还有其他想法吗?nodehttp代理昨天有8200次下载!当然,有人正在使用今年的Node构建并代理websocket。。。。
我到底在找什么
我想实现一个代理服务器(最好是Node),它代理多个Node.js工作程序,并通过基于浏览器cookie的粘性会话路由请求。此代理需要稳定地支持传统请求以及web套接字。
或者
如果可行的话,我不介意通过集群节点工作程序来完成上述操作。我唯一真正的要求是基于请求头中的cookie来维护粘性会话。
如果有比我尝试的更好的方法来完成上面的任务,我完全支持。
通常我不认为node不是最常用的代理服务器选项,我使用nginx作为node的前端服务器,这是一个非常好的组合。以下是一些安装和使用nginx粘性会话模块的说明。
它是一个轻量级的前端服务器,具有类似json的配置,坚固且测试良好。
如果您想提供静态页面css,nginx的速度也要快得多。它是配置缓存头、根据域将流量重定向到多个服务器、粘性会话、压缩css和javascript等的理想选择。
您也可以考虑像HAProxy这样的纯负载平衡开源解决方案。无论如何,我不认为node是最好的工具,最好只使用它来实现后端,并在它前面放一些类似nginx的东西来处理通常的前端服务器任务。
我同意六氰化物。对我来说,通过redis之类的服务或某种消息查询系统对工作人员进行排队是最有意义的。工作人员将通过Redis Pub/Sub功能由web节点(代理)排队。工作人员会在出现错误时进行回调、完成或通过"数据"事件实时流式传输数据。也许去图书馆看看吧。你也可以推出自己的类似库。RabbitMQ是另一个用于类似目的的系统。
我使用socket.io,如果你已经在使用这项技术,但你需要将工具用于预期目的。Redis或MQ系统将是最有意义的,并与websocket(socket.io)配合使用,创建实时、深入的应用程序。
会话亲和性(粘性会话)通过aws的Elastic LoadBalancer支持,这支持webSockets。PaaS提供商(Modulus)正是这样做的。还有satalite,它为节点http代理提供粘性会话,但我不知道它是否支持webSockets。
我自己也在研究类似的事情,目的是动态生成(和销毁)Node.js集群节点。
免责声明:我仍然不建议使用Node进行此操作;nginx对于您正在寻找的那种设计架构来说更稳定,甚至更稳定的是HAProxy(非常成熟,很容易支持粘性会话代理)。正如@tsturzl所指出的,有satellite
,但考虑到下载量很低,我会谨慎行事(至少在生产环境中)。
也就是说,由于您似乎已经用Node设置好了所有内容,因此重建和重新架构可能比它的价值更大。因此,要安装带有NPM:的caronte
分支
-
使用
npm uninstall node-proxy
和/或sudo npm -d uninstall node-proxy
删除以前的http-node-proxy
主安装 -
下载
caronte
分支.zip并提取它。 - 运行
npm -g install /path/to/node-http-proxy-caronte
- 在我的情况下,安装链接被破坏了,所以我不得不运行
sudo npm link http-proxy
我已经使用他们的基本代理示例启动并运行了它——无论这是否解决了您的丢弃会话问题,只有您自己知道。
- ajax请求的顺序总是不同的
- Meteor如何接收HTTP请求
- 有没有一种方法可以防止img get请求使用css或js发生
- 从ajax请求中获取javascript对象
- JSONP请求返回结果,但也触发error_callback
- 在localhost Dev Box上测试JSONP请求的最佳方式
- Ajax请求文档就绪会导致jquery加载缓慢
- MockJax没有在JavaScript应用程序中发送对我AJAX请求的响应
- chrome在WebSocket握手期间获取新错误
- 正在传递JSONP标头's数据参数到另一个文件中的AJAX请求
- 在openshift node js应用程序中获取请求
- 一个WebSocket请求应该有多大
- Node.js http代理删除websocket请求
- 为什么我在 WebSocket 握手请求标头中看不到 cookie 值
- WebSocket onMessage 在 AJAX 请求期间未触发
- 是否有将 WebSocket 请求转换为服务器上的 HTTP 请求的标准
- 谁正在发送http websocket升级请求
- 如何在Websocket中向所有连接的客户端发送请求
- Websocket上的erlang错误-总是将请求传递给loop而不是ws_loop
- 如何在javascript中通过websocket验证每个请求