使用Node http-proxy代理WebSocket连接

15

我有一个使用socket.io通过websockets的应用程序。对于我的应用程序,我想使用一个单独的HTTP服务器来提供静态内容和JavaScript。因此,我需要放置代理。

我正在使用node-http-proxy。作为起点,我的websockets应用程序正在8081端口上运行。我正在使用以下代码将socket.io通信重定向到这个独立服务器,同时使用express提供静态内容:

var http = require('http'),
    httpProxy = require('http-proxy'),
    express = require('express');

// create a server
var app = express();
var proxy = httpProxy.createProxyServer({ ws: true });

// proxy HTTP GET / POST
app.get('/socket.io/*', function(req, res) {
  console.log("proxying GET request", req.url);
  proxy.web(req, res, { target: 'http://localhost:8081'});
});
app.post('/socket.io/*', function(req, res) {
  console.log("proxying POST request", req.url);
  proxy.web(req, res, { target: 'http://localhost:8081'});
});

// Proxy websockets
app.on('upgrade', function (req, socket, head) {
  console.log("proxying upgrade request", req.url);
  proxy.ws(req, socket, head);
});

// serve static content
app.use('/', express.static(__dirname + "/public"));

app.listen(8080);

上述应用程序运行得很正常,然而我发现socket.io不再使用WebSockets,而是退而求其次采用XHR轮询。

从代理代码的日志记录中可以确认这一点:

proxying GET request /socket.io/1/?t=1391781619101
proxying GET request /socket.io/1/xhr-polling/f-VVzPcV-7_IKJJtl6VN?t=13917816294
proxying POST request /socket.io/1/xhr-polling/f-VVzPcV-7_IKJJtl6VN?t=1391781629
proxying GET request /socket.io/1/xhr-polling/f-VVzPcV-7_IKJJtl6VN?t=13917816294
proxying GET request /socket.io/1/xhr-polling/f-VVzPcV-7_IKJJtl6VN?t=13917816294

有没有人知道如何代理Web Sockets通信?所有来自node-http-proxy的示例都假设您想代理所有流量,而不是代理一些并服务其他流量。


1
个人而言,我使用nginx作为http服务器和代理。它非常适合websocket代理(这也是我从apache转换的原因)。 - Denys Séguret
1
@dystroy 谢谢你的提示 - 尽管我希望有一个基于节点的解决方案。这样开发人员就可以拥有一个反映实时部署的本地设置。 - ColinE
2个回答

24

我刚偶然发现了你的问题,发现它仍未得到解答。嗯,如果你还在寻找解决方案……

你代码中的问题是app.listen(8080)只是语法糖,实际上等同于

require('http').createServer(app).listen(8080)
虽然 app 本身只是一个处理程序函数,而不是 httpServer 的实例(我个人认为这个特性应该从 Express 中移除以避免混淆)。 因此,你的 app.on('upgrade') 实际上从未被使用。你应该改写成:
var server = require('http').createServer(app);
server.on('upgrade', function (req, socket, head) {
  proxy.ws(req, socket, head);
});
server.listen(8080);

希望能对您有所帮助。


1
这个完美地运作了!我创建了一个Gist,用于设置Browser-sync和Express:https://gist.github.com/timaschew/00ba49d3a39bc3dfbe8f - timaschew

-1
你需要两个服务器吗?如果不需要,你可以使用同一个服务器来处理静态文件和监听套接字连接:
// make the http server
var express = require('express'),
    app = express(), server = require('http').createServer(app),
    io;

// serve static content
server.use('/', express.static(__dirname + '/public'));

server.listen(8080);

// listen for socket connections
io = require('socket.io').listen(server);

// socket stuff here

1
是的,我知道我可以使用一个服务器 - 但整个重点在于,在生产中,流连接将来自不同的服务器!感谢您的意见 :-) - ColinE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接