Action cable unable to connect (Failed to upgrade to WebSocket )
Asked Answered
M

3

11

I am having a issue in connecting to websocket in non-development environments with these log messages

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

I debuggged a little and figured out the request sent by the browser/javascript is not exactly the same as the request received by unicorn(running with nginx).

The request header by the browser is

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

The connection here is 'upgrade' but the websocket request has the connection 'closed'(probably nginx is messing it up?)

And this piece of code in websocket driver is failing

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

Updates

This is my nginx configuration

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;
}

I have mounted actioncable server on /cable

mount ActionCable.server => "/cable"

With the nginx changes i am able to successfully have the handshake but the server is not able to send the heart beats and the connection keeps dropping.

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)
Microreader answered 5/7, 2016 at 23:51 Comment(7)
What version of Nginx are you running? I think WebSockets are supported since 1.3. Did you set Upgrade and Connection headers as nginx.com/blog/websocket-nginx suggests?Maemaeander
updated question !! @JuliuszGoneraMicroreader
This works for me with Nginx 1.7.12: gist.github.com/jgonera/91aa8c1f4e38bf0169ccc3adc00be90cMaemaeander
Thanks @JuliuszGonera my nginx configuration is working..but still not with unicorn it works with puma .. Whats your unicorn version?Microreader
Confirmed 2 things need to be done. As mentioned in the answer below, you need to set the config.action_cable.allowed_request_origins. Also, if your app is running behind nginx proxy, you need to proxy_set_header as mentioned by @juliuszGonera. See also nginx.org/en/docs/http/websocket.html.Arias
@Microreader When using Unicorn does the connection fail to upgrade to WebSocket or is it a different problem?Maemaeander
If you still have problems with Unicorn (in development) this might be the reason: github.com/rails/rails/issues/26179Maemaeander
H
3

Have you set the config.action_cable.allowed_request_origins in production.rb to allow connections from your production domain? In my nginx.conf there is also

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

I am not entirely sure if they are really required, but it works for me.

Huberthuberto answered 11/7, 2016 at 19:21 Comment(0)
A
1

Rails 5 Action Cable CORS:

create a ruby file i.e action_cable.rb in my_rails_project/config/initializers and add the following code.

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

you are done.

Abuttals answered 9/6, 2017 at 9:53 Comment(0)
U
0

Thanks to above answer i was getting the similar error. Issue was that i kept backend url address in config.action_cable.allowed_request_origins on changing it to frontend url issue got resolved. To be more clear i am having font-end,backend in entirely different domains

Unchaste answered 14/2, 2020 at 15:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.