动作线无法连接(升级到 WebSocket 失败)

Posted

技术标签:

【中文标题】动作线无法连接(升级到 WebSocket 失败)【英文标题】:Action cable unable to connect (Failed to upgrade to WebSocket ) 【发布时间】:2016-11-07 22:44:44 【问题描述】:

我在使用这些日志消息连接到非开发环境中的 websocket 时遇到问题

Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: close, HTTP_UPGRADE: )

Finished "/cable/"[non-WebSocket] for 127.0.0.1 at 2016-07-06 09:44:29 +1000

我调试了一下,发现浏览器/javascript发送的请求与unicorn(使用nginx运行)收到的请求不完全相同。

浏览器的请求头是

GET ws://cc-uat.com.au/cable HTTP/1.1
Host: cc-uat.com.au
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://cc-uat.com.au
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/49.0.2623.87 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
Cookie: <Lot of cookies>
Sec-WebSocket-Key: QGdJkYIA2u7vtmMVXfHKtQ==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Protocol: actioncable-v1-json, actioncable-unsupported

这里的连接是“升级”,但是 websocket 请求的连接是“关闭”的(可能是 nginx 搞砸了?)

而 websocket 驱动程序中的这段代码失败了

def self.websocket?(env)
      connection = env['HTTP_CONNECTION'] || ''
      upgrade    = env['HTTP_UPGRADE']    || ''

      env['REQUEST_METHOD'] == 'GET' and
      connection.downcase.split(/ *, */).include?('upgrade') and
      upgrade.downcase == 'websocket'
end

更新

这是我的 nginx 配置

upstream app 
    server unix:/home/osboxes/sites/actioncable-examples/shared/sockets/unicorn.sock fail_timeout=0;


server 
    listen 80;
    server_name localhost;

    root /home/osboxes/sites/actioncable-example/public;

    try_files $uri/index.html $uri @app;

    location @app 
        proxy_pass http://app;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_http_version 1.1;
     proxy_set_header Upgrade $http_upgrade;
     proxy_set_header Connection "upgrade";
    


    error_page 500 502 503 504 /500.html;
    client_max_body_size 4G;
    keepalive_timeout 10;

我在 /cable 上安装了 actioncable 服务器

mount ActionCable.server => "/cable"

通过 nginx 更改,我能够成功握手,但服务器无法发送心跳,并且连接不断下降。

Started GET "/cable" for 127.0.0.1 at 2016-07-07 05:48:06 +0100
Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2016-07-07 05:48:06 +0100
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)

【问题讨论】:

你运行的是什么版本的 Nginx?我认为从 1.3 开始就支持 WebSockets。您是否按照nginx.com/blog/websocket-nginx 的建议设置了UpgradeConnection 标头? 更新问题!! @JuliuszGonera 这适用于我的 Nginx 1.7.12:gist.github.com/jgonera/91aa8c1f4e38bf0169ccc3adc00be90c 感谢@JuliuszGonera,我的 nginx 配置正在运行..但仍然不能与 unicorn 一起使用,它可以与 puma 一起使用 .. 你的 unicorn 版本是什么? 确认需要做两件事。如以下答案所述,您需要设置config.action_cable.allowed_request_origins。此外,如果您的应用程序在 nginx 代理后面运行,您需要像 @juliuszGonera 提到的那样使用 proxy_set_header。另请参阅 nginx.org/en/docs/http/websocket.html。 【参考方案1】:

您是否在 production.rb 中设置了 config.action_cable.allowed_request_origins 以允许来自您的生产域的连接? 在我的 nginx.conf 中也有

proxy_set_header X-Real-IP $remote_addr;  
proxy_set_header X-Forwarded-Proto http;

我不完全确定它们是否真的需要,但它对我有用。

【讨论】:

【参考方案2】:

Rails 5 动作电缆 CORS:

my_rails_project/config/initializers 中创建一个ruby 文件,即action_cable.rb 并添加以下代码。

if Rails.env.development?
  Rails.application.config.action_cable.allowed_request_origins =  ['http://localhost:3001', 'http://127.0.0.1:3001']
end

你已经完成了。

【讨论】:

【参考方案3】:

感谢above answer 我遇到了类似的错误。问题是我将后端 url 地址保留在 config.action_cable.allowed_request_origins 中,将其更改为前端 url 问题得到了解决。更清楚地说,我在完全不同的域中拥有字体端和后端

【讨论】:

以上是关于动作线无法连接(升级到 WebSocket 失败)的主要内容,如果未能解决你的问题,请参考以下文章

无法启动连接:错误:WebSocket 连接失败

Android websocket连接失败

WebSocket无法建立到服务器的连接?

我无法在 Rails 中注册设计

Exchange2010 升级到 2016,2010用户无法通过2016代理访问邮箱,导致连接失败。

如何使用WebSocket