基于 Socket.io 的应用程序 运行 通过节点代理服务器断开连接时断开所有套接字
Socket.io-based app running through node proxy server disconnecting all sockets whenever one disconnects
我使用 node.js
、express
和 socket.io
制作了一个基本的聊天应用程序。它与 socket.io 的 tutorial chat app 没有太大区别,它只是在连接的客户端之间发出事件。当我 运行 它在我的服务器上的端口 3001 上时,它工作正常。
然后我使用 node-http-proxy
创建了一个代理服务器应用程序,它侦听端口 80 并根据请求 url 将流量重定向到我在不同端口上有 运行 的各种独立节点应用程序.非常简单。但是有什么东西坏了。每当有人断开连接时,每个套接字 都会断开并重新连接。这对我的聊天应用程序不利,它具有基于连接的事件。客户端控制台全部显示:
WebSocket connection to 'ws://[some socket info]' failed: Connection closed before receiving a handshake response
以下是我认为代码的重要部分。
代理-server.js
var http = require('http');
var httpProxy = require('http-proxy');
//create proxy template object with websockets enabled
var proxy = httpProxy.createProxyServer({ws: true});
//check the header on request and return the appropriate port to proxy to
function sites (req) {
//webapps get their own dedicated port
if (req == 'mychatwebsite.com') {return 'http://localhost:3001';}
else if (req == 'someothersite.com') {return 'http://localhost:3002';}
//static sites are handled by a vhost server on port 3000
else {return 'http://localhost:3000';}
}
//create node server on port 80 and proxy to ports accordingly
http.createServer(function (req, res) {
proxy.web(req, res, { target: sites(req.headers.host) });
}).listen(80);
聊天-app.js
/*
...other modules
*/
var express = require("express");
var app = exports.app = express(); //I probably don't need "exports.app" anymore
var http = require("http").Server(app);
var io = require("socket.io")(http);
io.on("connection", function (socket) {
/*
...fun socket.on and io.emit stuff
*/
socket.on("disconnect", function () {
//say bye
});
});
http.listen(3001, function () {
console.log("listening on port 3001");
});
现在从我在 socket.io's site, I might need to use something to carry the socket traffic through my proxy server. I thought that node-http-proxy did that for me with the {ws: true}
option as it states in their docs 上读到的内容来看,但显然它并没有像我想象的那样工作。 socket.io 提到了三个不同的东西:
sticky session
基于节点的内置 cluster
模块
socket.io-redis
,允许单独的 socket.io 个实例相互通信
socket.io-emitter
,它允许 socket.io 与非 socket.io 进程对话
我完全不知道这意味着什么或做什么。我不小心在这里编码超出了我的技能水平,我不知道这些工具中的哪一个可以解决我的问题(如果有的话),甚至不知道我的问题的真正原因是什么。
义务道歉:我是新手node.js,请见谅
也是强制性的:我知道像 nginx 这样的其他应用程序可以解决我的很多问题,但我的目标是在开始使用新工具之前学习和了解如何使用这套工具。而且,我使用的应用程序越少越好。
我认为您关于需要“通过代理服务器传输套接字流量”的直觉是正确的。为了建立一个 websocket,客户端发出一个带有特殊 Upgrade
header 的 HTTP 请求,向服务器发出信号以切换协议 (RFC 6455)。在节点中,http.Server
个实例在发生这种情况时发出 upgrade
事件,如果未处理该事件,连接将立即关闭。
您需要在您的 http 服务器上侦听 upgrade
事件并处理它:
var proxy = httpProxy.createProxyServer({ws: true})
var http = http.createServer(/* snip */).listen(80)
// handle upgrade events by proxying websockets
// something like this
http.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head, {target:sites(req.headers.host)})
})
有关更多信息,请参阅 node docs on the upgrade event and the node-http-proxy docs。
我使用 node.js
、express
和 socket.io
制作了一个基本的聊天应用程序。它与 socket.io 的 tutorial chat app 没有太大区别,它只是在连接的客户端之间发出事件。当我 运行 它在我的服务器上的端口 3001 上时,它工作正常。
然后我使用 node-http-proxy
创建了一个代理服务器应用程序,它侦听端口 80 并根据请求 url 将流量重定向到我在不同端口上有 运行 的各种独立节点应用程序.非常简单。但是有什么东西坏了。每当有人断开连接时,每个套接字 都会断开并重新连接。这对我的聊天应用程序不利,它具有基于连接的事件。客户端控制台全部显示:
WebSocket connection to 'ws://[some socket info]' failed: Connection closed before receiving a handshake response
以下是我认为代码的重要部分。
代理-server.js
var http = require('http');
var httpProxy = require('http-proxy');
//create proxy template object with websockets enabled
var proxy = httpProxy.createProxyServer({ws: true});
//check the header on request and return the appropriate port to proxy to
function sites (req) {
//webapps get their own dedicated port
if (req == 'mychatwebsite.com') {return 'http://localhost:3001';}
else if (req == 'someothersite.com') {return 'http://localhost:3002';}
//static sites are handled by a vhost server on port 3000
else {return 'http://localhost:3000';}
}
//create node server on port 80 and proxy to ports accordingly
http.createServer(function (req, res) {
proxy.web(req, res, { target: sites(req.headers.host) });
}).listen(80);
聊天-app.js
/*
...other modules
*/
var express = require("express");
var app = exports.app = express(); //I probably don't need "exports.app" anymore
var http = require("http").Server(app);
var io = require("socket.io")(http);
io.on("connection", function (socket) {
/*
...fun socket.on and io.emit stuff
*/
socket.on("disconnect", function () {
//say bye
});
});
http.listen(3001, function () {
console.log("listening on port 3001");
});
现在从我在 socket.io's site, I might need to use something to carry the socket traffic through my proxy server. I thought that node-http-proxy did that for me with the {ws: true}
option as it states in their docs 上读到的内容来看,但显然它并没有像我想象的那样工作。 socket.io 提到了三个不同的东西:
sticky session
基于节点的内置cluster
模块socket.io-redis
,允许单独的 socket.io 个实例相互通信socket.io-emitter
,它允许 socket.io 与非 socket.io 进程对话
我完全不知道这意味着什么或做什么。我不小心在这里编码超出了我的技能水平,我不知道这些工具中的哪一个可以解决我的问题(如果有的话),甚至不知道我的问题的真正原因是什么。
义务道歉:我是新手node.js,请见谅
也是强制性的:我知道像 nginx 这样的其他应用程序可以解决我的很多问题,但我的目标是在开始使用新工具之前学习和了解如何使用这套工具。而且,我使用的应用程序越少越好。
我认为您关于需要“通过代理服务器传输套接字流量”的直觉是正确的。为了建立一个 websocket,客户端发出一个带有特殊 Upgrade
header 的 HTTP 请求,向服务器发出信号以切换协议 (RFC 6455)。在节点中,http.Server
个实例在发生这种情况时发出 upgrade
事件,如果未处理该事件,连接将立即关闭。
您需要在您的 http 服务器上侦听 upgrade
事件并处理它:
var proxy = httpProxy.createProxyServer({ws: true})
var http = http.createServer(/* snip */).listen(80)
// handle upgrade events by proxying websockets
// something like this
http.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head, {target:sites(req.headers.host)})
})
有关更多信息,请参阅 node docs on the upgrade event and the node-http-proxy docs。