Nginx 在建立 ActionCable 连接后立即丢弃它们

Posted

技术标签:

【中文标题】Nginx 在建立 ActionCable 连接后立即丢弃它们【英文标题】:Nginx drops ActionCable connections immediately after they're established 【发布时间】:2020-05-21 13:55:33 【问题描述】:

使用 puma 和在 nginx 后面运行的 Rails 6。 nginx 配置如下所示:

upstream APPNAME 
  server unix:/tmp/APPNAME.sock fail_timeout=0;


server 
  listen 443 ssl;
  # ... server_name, ssl_certificate, etc.
  location /cable 
    proxy_pass http://APPNAME;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
  
  location @APPNAME 
    proxy_pass http://APPNAME;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $http_host;
    proxy_redirect off;
  

当ActionCable 连接来自浏览器时,它能够订阅频道并接收响应。但它永远不会收到任何“ping”消息,并且会继续重新连接(在我的情况下每 10 秒一次)。

使用curl直接测试连接,当直接在服务器上运行puma时它可以正常工作(在本地主机端口上,因为配置使用Unix套接字)。

time curl --trace-ascii curl-dump.txt -i -k -N \
  -H "Host: <REPLACE_WITH_HOSTNAME>" \
  -H "Connection: Upgrade" \
  -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Sec-WebSocket-Key: BOGUS+KEY+HERE+IS+FINE==" \
  http://localhost:3000/cable

但是当连接 URL 改为指向 nginx 端口号时,结果类似于浏览器:它永远不会收到任何“ping”消息。

【问题讨论】:

【参考方案1】:

我曾假设location @APPNAME 部分中的配置将用于调用proxy_pass 的其他位置,但回想起来我发现它根本不是,这就是必须重复proxy_set_header 指令的原因。

所以location /cable 部分需要包含使location @APPNAME 正常工作的所有 指令。我发现添加proxy_redirect off; 解决了这个问题。

所以下面的位置配置解决了这个问题:

  location /cable 
    proxy_pass http://APPNAME;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $http_host;
    proxy_redirect off;
  

【讨论】:

以上是关于Nginx 在建立 ActionCable 连接后立即丢弃它们的主要内容,如果未能解决你的问题,请参考以下文章

Rails5 + ActionCable:与'ws:// {hostname} / cable'的WebSocket连接失败:WebSocket在建立连接之前关闭

如何在生产中使用 Nginx 和 Unicorn 配置 ActionCable?

无法连接到 Elastic Beanstalk 上的 ActionCable

ActionCable:检测客户端连接丢失,向用户显示连接状态

ActionCable 中的多个连接

ActionCable 超时 - Heroku 上的“空闲连接”