Node.js Nodejs+;Socket.io+;Nginx反向代理不工作

Node.js Nodejs+;Socket.io+;Nginx反向代理不工作,node.js,nginx,socket.io,Node.js,Nginx,Socket.io,我正在将Nginx反向代理设置为NodeJS应用程序,该应用程序在托管其他NodeJS应用程序的服务器上包含Socket.IO NodeJS通过端口3001上的PM2运行。以下是Nginx配置: server { listen 80; server_name iptv-staging.northpoint.org; location / { proxy_set_header X-Forwarded-For $prox

我正在将Nginx反向代理设置为NodeJS应用程序,该应用程序在托管其他NodeJS应用程序的服务器上包含Socket.IO

NodeJS通过端口3001上的PM2运行。以下是Nginx配置:

server {
        listen 80;
        server_name iptv-staging.northpoint.org;
        location / {
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;

                proxy_pass http://localhost:3001;

                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
}
直接通过服务器的IP地址运行应用程序时
http://xxx.xxx.xxx.xxx:3001/
一切正常运行。来自Socket.IO的Ping/Pong请求约为50ms(默认pingTimeout为5000ms)。通过其DNS名称访问应用程序时
http://iptv-staging.northpoint.org
客户端报告ping超时并断开连接。它将在第一次尝试时重新连接,然后在第一次ping/pong请求时再次断开连接


据我所知,问题必须与Ngnix反向代理以及WebSocket如何路由有关。似乎服务器对ping请求的响应并没有发送给客户端。但我似乎无法确定原因。非常感谢您的帮助。

我也遇到了同样的问题。一个同事提供了答案,老实说,我没有完全理解,所以我没有信用,但我希望我能从代码中挑出答案

首先,我在服务器上创建了一个返回URI信息的API端点。这是告诉客户端使用什么地址连接的关键

apiRoutes.get('/options', (req, res) => {

  Log.info('Received request for app options.');

  // This isn't applicable to you, just showing where options declared.
  let options = JSON.parse(JSON.stringify(config.get('healthcheck.options')));

  // Decide what port to use.  It might be a port for a dev instance or from Env
  if ((process.env.PORT !== options.port) && (process.env.PORT > 0)) {
    options.port = process.env.PORT;
  }

  // This is the important bit...
  var internalUri = req.originalUrl;
  var externalUri = req.get('X-Real-URI') || internalUri;
  options.basePath = externalUri.substr(0, externalUri.length - internalUri.length + 1);

  res.status(200).send(JSON.stringify(options));
});
我的客户端是一个React应用程序,你会想你需要如何实现,但我是这样做的

这是我的“助手”函数,用于调用选项服务

export async function getOptions() {

  const res = await axios.get('/api/options');

  return res.data;

}
在我的React页面中,当页面加载时,我调用这个

componentDidMount() {

    getOptions()
        .then((res) => {
            this.setState({ port: res.port });

        // Call a client-side function to build URL.  Incl later.
        const socketUrl = getSocketUrl(res.port);

        console.log(`Attempting to connect to sockets at ${socketUrl}.`);

        // This is where it all comes together...
        const socket = io(socketUrl, { path: `${res.basePath}socket.io` });
        socket.on('connect', function () { console.log(`Connected to ${socketUrl}`); });

        socket.on('message', (result) => {
          console.log(result);
        });

        socket.on('data', (result) => {
          console.log(`Receiving next batch of results.`);

          const filteredResults = JSON.parse(result));

          // Do something with the results here...

        });

    });

.....
最后,getSocketUrl函数

function getSocketUrl(port) {

  console.log(`${window.location.hostname}`);

  if (window.location.hostname.toString().includes('local')) {
    return `localhost:${port}`;
  }

  return `${window.location.hostname}`;

}

这是一个有趣的方法。我尝试了它(做了一些修改),但是在我的笔记本电脑(socketio正常工作时)和通过nginx的登台服务器(根据最初的问题,它不工作时)上,客户端基本路径都返回为“/”。当您实现这一点时,您的开发机器和登台(服务器)环境之间的基本路径是否会改变?它确实会改变。dev服务器是一个没有意义的服务器名,但是在Prod上使用NGinx时,它有一个有意义的域名。另外,Dev服务器有一个端口号,而Prod没有,或者说端口号被Prod域名屏蔽了。和你一样,我最初的套接字解决方案在Dev上也不错,但在Prod上无法连接。这是高级开发人员使用的解决方案,以便套接字可以在任何一台服务器上工作。还值得注意的是,Prod中只有一个应用程序实例,并且没有使用端口范围进行负载平衡,因为这会增加复杂性。我尝试了几种组合,但未能实现在我的环境中工作。使用Docker将项目容器化,为其提供唯一的IP,而不使用反向代理,这应该可以解决问题。谢谢你的意见!祝你好运,抱歉没用。