Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Action cable unable to connect (Failed to upgrade to WebSocket )

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)
like image 204
sethi Avatar asked Jul 05 '16 23:07

sethi


2 Answers

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.

like image 128
Kaleem Ullah Avatar answered Nov 06 '22 16:11

Kaleem Ullah


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.

like image 34
Marc Doerflinger Avatar answered Nov 06 '22 17:11

Marc Doerflinger