基于 Socket.io 的应用程序 运行 通过节点代理服务器断开连接时断开所有套接字

Socket.io-based app running through node proxy server disconnecting all sockets whenever one disconnects

我使用 node.jsexpresssocket.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 提到了三个不同的东西:

我完全不知道这意味着什么或做什么。我不小心在这里编码超出了我的技能水平,我不知道这些工具中的哪一个可以解决我的问题(如果有的话),甚至不知道我的问题的真正原因是什么。

义务道歉:我是新手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