简体   繁体   English

Socket.io无法通过Cloudflare / Nginx断开连接

[英]Socket.io not disconnecting through Cloudflare/Nginx

I have a small web app that's served with Express.js and connects to the backend with Socket.io. 我有一个随Express.js一起提供的小型Web应用程序,并通过Socket.io连接到后端。 To make it public, I'm using Nginx as a reverse proxy and then Cloudflare at the very front. 为了公开,我使用Nginx作为反向代理,然后在最前面使用Cloudflare。 The app relies on the disconnect event firing when the it's closed or reloaded to keep track of online users among other things. 该应用程序在关闭或重新加载时依赖于disconnect事件触发,以跟踪在线用户等。 When going through Nginx and Cloudflare the disconnect event never fires on the backend. 通过Nginx和Cloudflare时,断开事件永远不会在后端触发。 It does when developing locally. 在本地开发时会这样做。

Here's my Nginx config file: 这是我的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
}

And here's a snippet of my server-side code: 这是我的服务器端代码的一个片段:

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

  socket.on('disconnect', () => {
    console.log('disconnected!')
    // Stuff that relies on the disconnect event
  })
})

When the user closes the tab or reloads the page the disconnect event should fire, but it never does when passing the connection through Nginx and Cloudflare. 当用户关闭选项卡或重新加载页面时,断开事件应触发,但在通过Nginx和Cloudflare传递连接时则不会触发。 Thanks in advance for any help! 在此先感谢您的帮助!

UPDATE: It seems like a few seconds after reloading/closing the disconnect event finally registers. 更新:重新加载/关闭断开事件似乎在几秒钟后终于注册了。

You have to add upgrade headers to your socket io path in nginx configuration it like this, 您必须像这样在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";
    }

Since you asked for a extension of the answer, first thing which you may already know is socket.io is a protocol that use Websockets protocol under the hood (so both are the same). 因为您要求扩展答案,所以您可能已经知道的第一件事就是socket.io是一个在后台使用Websockets协议的协议(因此两者是相同的)。 As standards both Websockets protocols and HTTP protocols is listening on the same port 80 or 443. The default protocol is HTTP, if user wants to use websockets protocol he/she has to send a upgrade request from HTTP to WS protocol and there is some key authentication and steps. 作为标准,Websockets协议和HTTP协议都在同一端口80或443上侦听。默认协议是HTTP,如果用户要使用Websockets协议,则他/她必须将升级请求从HTTP发送到WS协议,并且存在一些密钥身份验证和步骤。

That's why you need to put them in your nginx configuration. 这就是为什么需要将它们放入nginx配置中的原因。

Refer this if you need more information abouth Protocol upgrade mechanism. 如果您需要有关协议升级机制的更多信息,请参考此内容

Even though in my opinion, this is not a exact duplicate of this question, I feel obligated to give credits for @Paulo to providing the perfect answer even though is not accepted. 即使在我看来,这并不是问题的完全重复,但我仍然认为@Paulo有义务提供完美的答案,即使它没有被接受。

What is probably happening is 2 things. 可能正在发生的是两件事。

1st: Socket.io has a long timeout (hence the several seconds) and is looking to reconnect before declaring that it has been disconnected. 1st:Socket.io超时时间很长(因此需要几秒钟),并且在声明已断开连接之前希望重新连接。 Check for a reconnect_attempt or reconnecting event (note I have not used socket.io in a while, so I could be wrong on the timing for this) 检查是否存在reconnect_attempt或reconnecting事件(请注意我已经有一段时间没有使用过socket.io了,所以在时间上我可能是错误的)

2nd: You are not telling socket.io that it is disconnecting upon closing the browser window. 第二:您没有告诉socket.io在关闭浏览器窗口时断开连接。

I would recommend adding an event listener to your javascript that will tell your server that it is being disconnected upon window close. 我建议向您的JavaScript添加一个事件侦听器,该事件侦听器将告诉您的服务器它在关闭窗口时已断开连接。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM