Node.js http-proxy 丢弃 websocket 请求 [英] Node.js http-proxy drops websocket requests

查看:19
本文介绍了Node.js http-proxy 丢弃 websocket 请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我已经花了一个多星期的时间试图解决这个问题,但无济于事,所以如果有人有线索,你就是个英雄.这不会是一个容易回答的问题,除非我是个笨蛋.

Okay, I've spent over a week trying to figure this out to no avail, so if anyone has a clue, you are a hero. This isn't going to be an easy question to answer, unless I am being a dunce.

我正在使用 node-http-proxy 将粘性会话代理到在不同端口上运行的 16 个 node.js 工作程序.

I am using node-http-proxy to proxy sticky sessions to 16 node.js workers running on different ports.

我使用 Socket.IO 的 Web Sockets 来处理一堆不同类型的请求,也使用传统的请求.

I use Socket.IO's Web Sockets to handle a bunch of different types of requests, and use traditional requests as well.

当我将我的服务器切换到通过 node-http-proxy 代理时,有时会出现一个新问题,我的 Socket.IO 会话无法建立连接.

When I switched my server over to proxying via node-http-proxy, a new problem crept up in that sometimes, my Socket.IO session cannot establish a connection.

我真的无法在我的一生中稳定地复制它,唯一的方法就是将大量流量从多个客户端发送到服务器.

I literally can't stably reproduce it for the life of me, with the only way to turn it on being to throw a lot of traffic from multiple clients to the server.

如果我重新加载用户的浏览器,它有时可以重新连接,有时不能.

If I reload the user's browser, it can then sometimes re-connect, and sometimes not.

我必须代理粘性会话,因为我的应用程序基于每个工作人员进行身份验证,因此它根据其 Connect.SID cookie 路由请求(我使用的是 connect/express).

I have to proxy sticky sessions as my app authenticates on a per-worker basis, and so it routes a request based on its Connect.SID cookie (I am using connect/express).

这是我的 proxy.js 文件,它在节点中运行并路由到每个工作人员:

This is my proxy.js file that runs in node and routes to each of the workers:

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
  });

});

客户端/现象

套接字连接如下:

Client Side / The Phenomena

Socket connects like so:

var socket = io.connect('http://whatever:8888');

登录大约 10 秒后,我在此侦听器上再次收到此错误消息,这没有太大帮助.

After about 10 seconds on logging on, I get this error back on this listener, which doesn't help much.

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 请求永远不会回来 - 它只是挂起,即使在错误回来之后,它看起来像一个超时错误.服务器从不响应.

The Socket.IO GET request that the browser sends never comes back - it just hangs in pending, even after the error comes back, so it looks like a timeout error. The server never responds.

这就是工作人员接收套接字请求的方式.很简单.所有工人都有相同的代码,所以你认为他们中的一个人会收到请求并确认......

This is how a worker receives a socket request. Pretty simple. All workers have the same code, so you think one of them would get the request and acknowledge it...

app.sio.socketio.sockets.on('connection', function (socket) {
  // works... some of the time! all of my workers run this
  // exact same process.
});

总结

这是大量数据,我怀疑有人愿意面对它,但我完全被难住了,不知道下一步要检查哪里,下一步记录,无论如何,以解决它.我已经尝试了所有我知道的方法来查看问题所在,但无济于事.

Summary

That's a lot of data, and I doubt anyone is willing to confront it, but i'm totally stumped, don't know where to check next, log next, whatever, to solve it. I've tried everything I know to see what the problem is, to no avail.

好的,我很确定问题出在 node-http-proxy github 主页:

Okay, I am fairly certain that the problem is in this statement on the node-http-proxy github homepage:

node-http-proxy 与 <= 0.8.x 兼容,如果您正在寻找 >=0.10兼容版本请查看caronte

node-http-proxy is <= 0.8.x compatible, if you're looking for a >= 0.10 compatible version please check caronte

我正在运行 Node.js v0.10.13,这种现象与某些人在 github 问题中对此主题的评论完全一样:它只是随机丢弃 websocket 连接.

I am running Node.js v0.10.13, and the phenomena is exactly as some have commented in github issues on this subject: it just drops websocket connections randomly.

我已经尝试实现 Caronte,较新的"分支,但它根本没有记录在案,我已尽最大努力将他们的文档拼凑成一个可行的解决方案,但我无法让它转发 websocket,我的 Socket.IO 降级为轮询.

I've tried to implement caronte, the 'newer' fork, but it is not at all documented and I have tried my hardest to piece together their docs in a workable solution, but I can't get it forwarding websockets, my Socket.IO downgrades to polling.

关于如何实现和工作还有其他想法吗?node-http-proxy 昨天有 8200 次下载!肯定有人在使用今年的 Node 版本并代理 websockets....

Are there any other ideas on how to get this implemented and working? node-http-proxy has 8200 downloads yesterday! Sure someone is using a Node build from this year and proxying websockets....

我想完成一个代理服务器(最好是 Node),它代理多个 node.js 工作人员,并通过基于浏览器 cookie 的粘性会话路由请求.该代理需要稳定支持传统请求和网络套接字.

I want to accomplish a proxy server (preferrably Node) that proxies to multiple node.js workers, and which routes the requests via sticky sessions based on a browser cookie. This proxy would need to stably support traditional requests as well as web sockets.

如果可行,我不介意通过集群节点工作器完成上述任务.我唯一真正的要求是根据请求标头中的 cookie 维护粘性会话.

I don't mind accomplishing the above via clustered node workers, if that works. My only real requirement is maintaining sticky sessions based on a cookie in the request header.

如果有比我正在尝试的更好的方法来完成上述任务,我完全赞成.

If there is a better way to accomplish the above than what I am trying, I am all for it.

推荐答案

总的来说,我不认为 node 不是最常用的代理服务器选项,我使用 nginx 作为 node 的前端服务器,这是一个非常棒的组合.这里有一些说明安装并使用 nginx 粘性会话模块.

In general I don't think node is not the most used option as a proxy server, I, for one use nginx as a frontend server for node and it's a really great combination. Here are some instructions to install and use the nginx sticky sessions module.

这是一个轻量级的前端服务器,具有类似 json 的配置,可靠且经过良好测试.

It's a lightweight frontend server with json like configuration, solid and very well tested.

如果你想提供静态页面,css,nginx 也快很多.非常适合配置缓存标头、根据域、粘性会话将流量重定向到多个服务器、压缩 css 和 javascript 等.

nginx is also a lot faster if you want to serve static pages, css. It's ideal to configure your caching headers, redirect traffic to multiple servers depending on domain, sticky sessions, compress css and javascript, etc.

您还可以考虑使用纯负载平衡开源解决方案,例如 HAProxy.无论如何,我不相信 node 是最好的工具,最好只用它来实现你的后端,并在它前面放一些像 nginx 这样的东西来处理通常的前端服务器任务.

You could also consider a pure load balancing open source solution like HAProxy. In any case I don't believe node is the best tool for this, it's better to use it to implement your backend only and put something like nginx in front of it to handle the usual frontend server tasks.

这篇关于Node.js http-proxy 丢弃 websocket 请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆