【问题标题】:Socket.io with Nodejs not working with nginx reverse proxy带有 Nodejs 的 Socket.io 不能与 nginx 反向代理一起使用
【发布时间】:2021-04-26 09:01:16
【问题描述】:

我有一个带有 Express 和 Socket.io (Ubuntu 18.04) 的 Nodejs 服务器应用程序。在 nGinx (1.14) 反向代理进入现场之前,它一直运行良好。 nginx 服务器运行在 Node.js 应用程序的不同机器上,每个应用程序都在它自己的 vm 上,在同一个网络中。

2.1.1 版本的服务器和客户端。

nginx 服务器负责多个应用重定向。

我尝试了几种配置组合,但没有任何效果。

这是我尝试过的(“company1”的示例):

/etc/nginx/conf.d 中的default.conf

location /company1-srv/ {
     proxy_http_version 1.1;
     proxy_set_header Upgrade $http_upgrade;
     proxy_set_header Connection "Upgrade";
     proxy_set_header Host $host;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-Proto $scheme;
     proxy_set_header X-NginX-Proxy true;
     proxy_redirect off;
     proxy_pass http://172.16.0.25:51001/;
}

然后在客户端代码中,我使用“路径”选项进行连接,因为 socket.io 放错了它的库路径。

// companySrv and URL is actually returned by another service (following code is for illustrative purposes):
let companyUrl = 'https://api.myserver.com/company1-srv';
let companySrv = '/company1-srv'; 

socket(companyUrl, {
      path: companySrv + '/socket.io/'
});

我还尝试删除路径选项并为 socket.io 配置了一个特定的 /location(用于测试目的):

location /socket.io/ {
   proxy_http_version 1.1;
   proxy_set_header Upgrade $http_upgrade;
   proxy_set_header Connection 'upgrade';
   proxy_set_header Host $host;
   proxy_cache_bypass $http_upgrade;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-Proto $scheme;
   proxy_set_header X-NginX-Proxy true;
   proxy_redirect off;
   proxy_pass http://172.16.0.25:51001/socket.io/;
}

没有任何效果。

它连接,但不发出任何东西。片刻之后(一分钟左右),它变得不可用,引发“断开连接”(原因:传输关闭)客户端事件。

服务器:

const io = require('socket.io')(https || http, {
   transports: ['polling', 'websocket'],
   allowUpgrades: true, 
   pingInterval: 60000*60*24, 
   pingTimeout: 60000*60*24
});

我还尝试编辑 nginx.conf 并编写“上游 socket_nodes { ...”并使用 proxy_pass http://socket_nodes。这没有任何意义,因为我需要根据公司进行准确的重定向,但为了进行测试,我做了,但效果不佳。

我需要做什么?

谢谢

【问题讨论】:

    标签: node.js nginx socket.io nginx-reverse-proxy


    【解决方案1】:

    我们还将socket.io 与来自ngnix 的反向代理一起使用。我可以分享一些我们的设置,也许它有助于排除一些问题。

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
    include /etc/nginx/modules-enabled/*.conf;
    
    events {
            worker_connections 768;
    }
    
    stream {
            log_format      basic   '$time_iso8601 $remote_addr '
                                    '$protocol $status $bytes_sent $bytes_received '
                                    '$session_time $upstream_addr '
                                    '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
            
            access_log /var/log/nginx/stream.log basic;
    }
    
    http {
    
            sendfile on;
            tcp_nopush on;
            tcp_nodelay on;
            keepalive_timeout 65;
            types_hash_max_size 2048;
    
            include /etc/nginx/mime.types;
            default_type application/octet-stream;
    
            ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
            ssl_prefer_server_ciphers on;
    
            access_log /var/log/nginx/access.log;
            error_log /var/log/nginx/error.log;
    
            gzip on;
    
            include /etc/nginx/conf.d/*.conf;
            include /etc/nginx/sites-enabled/*;
    
            ##
            # Server Blocks 
            ##
    
    
            # DOMAINEXAMPLE A
            server {
                    server_name exampleA.domain.com;
                    location / {
                            proxy_set_header        X-Forwarded-For $remote_addr;
                            proxy_set_header        Host $http_host;
                            proxy_pass              http://192.168.21.105:5050;
                     }
            }
    
            # DOMAINEXAMPLE B
            server {
                    server_name exampleB.domain.com;
                    location /api {
                            proxy_set_header        X-Forwarded-For $remote_addr;
                            proxy_set_header        Host $http_host;
                            proxy_pass              http://192.168.21.106:5050;
                    }
            }
    
         
    }
    

    这里最有趣的部分可能是服务器块

            # DOMAINEXAMPLE A
            server {
                    server_name exampleA.domain.com;
                    location / {
                            proxy_set_header        X-Forwarded-For $remote_addr;
                            proxy_set_header        Host $http_host;
                            proxy_pass              http://192.168.21.105:5050;
                     }
            }
    
            # DOMAINEXAMPLE B
            server {
                    server_name exampleB.domain.com;
                    location /api {
                            proxy_set_header        X-Forwarded-For $remote_addr;
                            proxy_set_header        Host $http_host;
                            proxy_pass              http://192.168.21.106:5050;
                    }
            }
    

    域示例 A

    对于http://192.168.21.105:5050 的位置/,我们有一个NodeJS 进程正在运行,包括socket.io 的设置

    const express = require('express');
    const http    = require('http');
    const app     = express();
    const server  = http.createServer(app);
    const io      = require('socket.io')(server);
    

    域示例 B

    对于http://192.168.21.106:5050 的位置/api,我们正在运行另一个NodeJS 进程,其中socket.io 的设置略有不同

    const express  = require('express');
    const http     = require('http');
    const app      = express();
    const server   = http.createServer(app);
    const io       = require('socket.io')(server, {path: '/api/socket.io'});
    

    在这两种情况下,socket.io 都非常适合我们

    从客户端连接(示例 B)

    我们实际上在服务器端做的是为socket.io创建一个命名空间,比如

    const io= require('socket.io')(server, {path: '/api/socket.io'});
    const nsp = io.of('/api/frontend');
    

    然后在客户端,像这样连接到它

    import io from 'socket.io-client'
    const socket = io('https://exampleB.domain.com/api/frontend', {path: "/api/socket.io"});
    

    【讨论】:

    • 感谢分享帕斯卡。您使用的是什么版本的 socket.io?在示例 B 中,在客户端,您使用路径选项进行连接,对吗? io.connect(serverUrl, { path: '/api/socket.io' })
    • 在服务器 socket.io": "^2.3.0" 和客户端 "socket.io-client": "^2.3.0"。是的{path: "/api/socket.io"} 在客户端连接。我将更新我如何从客户端连接的答案。
    • @Lacoste 你能找到什么吗?我很好奇,解决您的问题可能也有助于我们更好地理解这一点:)
    • @EduMüller Socket.io 今年更新了他们的文档,你可能会找到答案hereThis is because the HTTP long-polling transport sends multiple HTTP requests during the lifetime of the Socket.IO session. - 所以我猜你猜对了,它一直在发送请求。他们还更新了 Reverse Proxy 的文档
    • @PascalLamers 你是对的。我正在使用配置为["polling", "websocket"] 的默认传输进行测试。当我把它放在没有反向代理的情况下运行时,这些各种请求都没有发生,但是当我把它放在反向代理上时。再读一点,我意识到这很正常,因为我在反向代理上的 websocket 配置无效,所以只使用了长轮询。不管怎样,谢谢你的回复。
    猜你喜欢
    • 2019-09-27
    • 1970-01-01
    • 2017-10-22
    • 2017-09-27
    • 2018-05-09
    • 2020-06-23
    • 2014-09-05
    • 2020-06-14
    • 2021-07-01
    相关资源
    最近更新 更多