Javascript Socket.io未通过Cloudflare/Nginx断开连接

Javascript Socket.io未通过Cloudflare/Nginx断开连接,javascript,node.js,nginx,socket.io,cloudflare,Javascript,Node.js,Nginx,Socket.io,Cloudflare,我有一个小的web应用程序,它由Express.js提供,并通过Socket.io连接到后端。为了公开,我使用Nginx作为反向代理,然后在最前端使用Cloudflare。当应用程序关闭或重新加载时,它依靠断开连接事件触发来跟踪在线用户。通过Nginx和Cloudflare时,断开连接事件不会在后端触发。在本地开发时,它会这样做 这是我的Nginx配置文件: server { listen 80; server_name colab.gq; server_name www

我有一个小的web应用程序,它由Express.js提供,并通过Socket.io连接到后端。为了公开,我使用Nginx作为反向代理,然后在最前端使用Cloudflare。当应用程序关闭或重新加载时,它依靠
断开连接
事件触发来跟踪在线用户。通过Nginx和Cloudflare时,断开连接事件不会在后端触发。在本地开发时,它会这样做

这是我的Nginx配置文件:

server {
    listen 80;
    server_name colab.gq;
    server_name www.colab.gq;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header X-Forwarded-For $remote_addr;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/colab.gq/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/colab.gq/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
下面是我的服务器端代码片段:

io.on('connection', (socket) => {
  // Stuff here

  socket.on('disconnect', () => {
    console.log('disconnected!')
    // Stuff that relies on the disconnect event
  })
})
当用户关闭选项卡或重新加载页面时,应该触发断开连接事件,但当通过Nginx和Cloudflare传递连接时,不会触发断开连接事件。提前感谢您的帮助


更新:似乎在重新加载/关闭断开连接事件后的几秒钟,断开连接事件终于注册。

您必须在nginx配置中将升级头添加到套接字io路径,如下所示

    location ~* \.io {
      .. your configuration

      proxy_pass http://localhost:3000;
      proxy_redirect off;

      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }

既然您要求对答案进行扩展,那么您可能已经知道的第一件事就是socket.io是一个在幕后使用Websockets协议的协议(因此两者都是相同的)。作为标准,Websockets协议和HTTP协议都在同一端口80或443上侦听。默认协议是HTTP,如果用户想要使用websockets协议,他/她必须发送一个从HTTP到WS协议的升级请求,并且有一些关键的身份验证和步骤

这就是为什么需要将它们放在nginx配置中

如果需要有关协议升级机制的更多信息,请参阅


尽管在我看来,这不是问题的完全重复,但我觉得有义务为提供完美答案而给予赞扬,即使答案不被接受。

您必须在nginx配置中向套接字io路径添加升级头,如下所示

    location ~* \.io {
      .. your configuration

      proxy_pass http://localhost:3000;
      proxy_redirect off;

      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }

既然您要求对答案进行扩展,那么您可能已经知道的第一件事就是socket.io是一个在幕后使用Websockets协议的协议(因此两者都是相同的)。作为标准,Websockets协议和HTTP协议都在同一端口80或443上侦听。默认协议是HTTP,如果用户想要使用websockets协议,他/她必须发送一个从HTTP到WS协议的升级请求,并且有一些关键的身份验证和步骤

这就是为什么需要将它们放在nginx配置中

如果需要有关协议升级机制的更多信息,请参阅


尽管在我看来,这并不是问题的完全复制品,但我觉得有义务对提供完美答案给予赞扬,即使答案不被接受。

可能发生的是两件事

第一:Socket.io有很长的超时时间(因此需要几秒钟),并且在声明它已断开连接之前,正在寻找重新连接。检查是否有重新连接尝试或重新连接事件(注意,我有一段时间没有使用socket.io了,因此我可能对此计时错误)

第二:您没有告诉socket.io它在关闭浏览器窗口时正在断开连接

我建议在javascript中添加一个事件监听器,它会告诉服务器在窗口关闭时正在断开连接

    window.addEventListener('beforeunload', () => {
       socket.disconnect();
    }

可能发生的是两件事

第一:Socket.io有很长的超时时间(因此需要几秒钟),并且在声明它已断开连接之前,正在寻找重新连接。检查是否有重新连接尝试或重新连接事件(注意,我有一段时间没有使用socket.io了,因此我可能对此计时错误)

第二:您没有告诉socket.io它在关闭浏览器窗口时正在断开连接

我建议在javascript中添加一个事件监听器,它会告诉服务器在窗口关闭时正在断开连接

    window.addEventListener('beforeunload', () => {
       socket.disconnect();
    }

我很好奇,你做了
Host
X-NginX-Proxy
吗?很抱歉我编辑了我的答案,升级标题在你的情况下就足够了啊,好的。注意你的编辑。介意解释一下升级的作用吗?我仍然会接受你的回答,但我很感兴趣。而且需要http版本。我很好奇,做
Host
X-NginX-Proxy
做什么?很抱歉我编辑了我的答案,升级标题在你的情况下就足够了啊,好的。注意你的编辑。介意解释一下升级的作用吗?仍然会接受你的答案,但我很感兴趣。需要http版本谢谢,但请看JKK的答案。这对我来说很有效,我已经尝试过类似于你推荐的东西。太棒了,我很高兴你得到了。谢谢,但请看JKK的答案。这对我来说很有效,我已经尝试过类似于你推荐的东西。太棒了,我很高兴你得到了。