Node.js 在网络库节点JS中获取请求的客户端ip

Node.js 在网络库节点JS中获取请求的客户端ip,node.js,nginx,socket.io,Node.js,Nginx,Socket.io,我在nginx后面的nodejs中使用粘性会话。 Sticky会话通过检查连接的remoteAddress来实现负载平衡。 现在的问题是它总是占用nginx服务器的ip server = net.createServer({ pauseOnConnect: true },function(c) { // Get int31 hash of ip var worker, ipHash = hash((c.remoteAddress || '').split(/\./g),

我在nginx后面的nodejs中使用粘性会话。 Sticky会话通过检查连接的remoteAddress来实现负载平衡。 现在的问题是它总是占用nginx服务器的ip

 server = net.createServer({ pauseOnConnect: true },function(c) {

  // Get int31 hash of ip
  var worker,
      ipHash = hash((c.remoteAddress || '').split(/\./g), seed);

  // Pass connection to worker
  worker = workers[ipHash % workers.length];
  worker.send('sticky-session:connection', c);
});
我们可以使用网络库获取客户端ip吗

Nginx配置:

 server {
    listen       80 default_server;
    server_name  localhost;
    root         /usr/share/nginx/html;
    #auth_basic "Restricted";
#auth_basic_user_file /etc/nginx/.htpasswd;
    #charset koi8-r;

    #access_log  /var/log/nginx/host.access.log  main;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    location / {
   set_real_ip_from 0.0.0.0/0;
   real_ip_header X-Forwarded-For;
  real_ip_recursive on;
    proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://socket_nodes;
    proxy_read_timeout 3000;

您正在使用的模块似乎还不支持使用反向代理源


看一看,一些pull请求似乎可以解决您的问题,因此您可以通过使用模块的fork(您可以)找到解决方案。

您正在使用的模块似乎还不支持反向代理源


看一看,一些pull请求似乎可以解决您的问题,因此您可以通过使用模块的fork(您可以)找到解决方案。

您正在使用的模块似乎还不支持反向代理源


看一看,一些pull请求似乎可以解决您的问题,因此您可以通过使用模块的fork(您可以)找到解决方案。

您正在使用的模块似乎还不支持反向代理源


看一看,一些pull请求似乎可以解决您的问题,因此您可以通过使用模块的fork(您可以)找到解决方案。

正如mef所指出的,目前,sticky session在反向代理之后不起作用,其中remoteAddress总是相同的。 上面提到的问题中的问题,以及之前的问题,可能确实解决了这个问题,尽管我还没有测试过自己

然而,这些修复依赖于部分解析数据包,在更高级别上查看报头的同时执行低级路由。。。正如pull请求上的注释所示,它们不稳定,依赖于未记录的行为,存在兼容性问题,可能会降低性能,等等

如果您不想依赖这样的实验性实现,另一种选择是将负载平衡完全留给nginx,nginx可以看到客户端的真实IP,从而保持会话的粘性。您所需要的只是nginx的内置ip_散列负载平衡

您的nginx配置可能如下所示:

upstream socket_nodes {
    ip_hash;
    server 127.0.0.1:8000;
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
    server 127.0.0.1:8004;
    server 127.0.0.1:8005;
    server 127.0.0.1:8006;
    server 127.0.0.1:8007;
}

server {
    listen       80 default_server;
    server_name  localhost;
    root         /usr/share/nginx/html;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    location / {
        # Note: Trusting all addresses like this means anyone
        # can pretend to have any address they want.
        # Only do this if you're absolutely certain only trusted
        # sources can reach nginx with requests to begin with.
        set_real_ip_from 0.0.0.0/0;

        real_ip_header X-Forwarded-For;
        real_ip_recursive on;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;

        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_pass http://socket_nodes;
        proxy_read_timeout 3000;
    }
}
现在,要使其正常工作,还需要对服务器代码进行一些修改:

if (cluster.isMaster) {
    var STARTING_PORT = 8000;
    var NUMBER_OF_WORKERS = 8;

    for (var i = 0; i < NUMBER_OF_WORKERS; i++) {
        // Passing each worker its port number as an environment variable.
        cluster.fork({ port: STARTING_PORT + i });
    }

    cluster.on('exit', function(worker, code, signal) {
        // Create a new worker, log, or do whatever else you want. 
    });
}
else {
    server = http.createServer(app);

    // Socket.io initialization would go here.

    // process.env.port is the port passed to this worker by the master.
    server.listen(process.env.port, function(err) {
        if (err) { /* Error handling. */ }
        console.log("Server started on port", process.env.port);
    });
}
if(cluster.isMaster){
var起始端口=8000;
工人的var数量=8;
对于(var i=0;i<工人数量;i++){
//将每个辅助进程的端口号作为环境变量传递。
fork({port:STARTING_port+i});
}
集群打开('exit',功能(工作者、代码、信号){
//创建一个新的工作程序、日志或执行任何您想要的操作。
});
}
否则{
server=http.createServer(app);
//Socket.io初始化将转到此处。
//process.env.port是主机传递给此辅助进程的端口。
侦听(process.env.port,函数(err){
if(err){/*错误处理。*/}
log(“服务器在端口上启动”,process.env.port);
});
}
不同之处在于,不是使用集群让所有工作进程共享一个端口(由集群本身平衡负载),而是每个工作进程都有自己的端口,nginx可以在不同的端口之间分配负载,以到达不同的工作进程

由于nginx根据它从客户机(或您的情况下的X-Forwarded-For报头)获得的IP选择要转到哪个端口,因此同一会话中的所有请求将始终以相同的进程结束

当然,这种方法的一个主要缺点是,工人数量的动态性大大降低。如果端口在nginx配置中是“硬编码”的,那么节点服务器必须确保始终严格侦听这些端口,不少于也不多于。如果没有一个好的系统来同步nginx配置和节点服务器,这就引入了错误的可能性,并使得动态扩展到环境中的核心数量变得更加困难

然后,我再次设想,可以通过编程方式生成/更新nginx配置来克服这个问题,因此它总是反映所需的进程数,或者可能通过为nginx配置大量端口,然后根据需要让每个节点工作线程侦听多个端口(因此,您仍然可以拥有与内核数量相同的工作人员)。然而,到目前为止,我还没有亲自验证或尝试实施这两种方法


关于代理后面的nginx服务器的说明 在您提供的nginx配置中,您似乎使用了ngx_http_realip_模块。虽然您在问题中没有明确提及这一点,但请注意,在nginx本身位于某种代理(例如ELB)后面的情况下,这实际上可能是必要的

然后需要使用
real\u ip\u header
指令来确保散列以选择要转到哪个端口的是真正的客户端ip(例如X-Forwarded-For),而不是其他代理

在这种情况下,nginx实际上提供了一个与sticky session的pull请求试图实现的目的非常相似的目的:使用头来做出负载平衡决策,特别是确保相同的真实客户端IP始终指向相同的进程


当然,关键的区别在于,nginx作为一个专用的web服务器、负载均衡器和反向代理,被设计来完成这类操作。解析和操作协议栈的不同层是它的主要任务。更重要的是,尽管还不清楚有多少人实际使用了这些pull-requ在EST、nginx中,它是稳定的、维护良好的,几乎在任何地方都可以使用。

正如mef所指出的,sticky session目前不能在反向代理之后工作,因为在反向代理中,remoteAddress总是相同的。 上面提到的问题中的问题,以及之前的问题,可能确实解决了这个问题,尽管我还没有测试过自己

然而,这些修复依赖于