WebSocket connection to 'ws://example.com/cable' failed: Unexpected response code: 404 - ruby-on-rails

I created a project on Rails 5.0.0.
Further I did absolutely the same as in this video: https://www.youtube.com/watch?v=n0WUjGkDFS0
Except for the generated channels. I generated two channels: chat and comment.
I also read it in parallel: https://github.com/rails/rails/tree/master/actioncable
In routes.rb I added this line:
mount ActionCable.server => '/cable'
In application.rb I added this line:
config.action_cable.mount_path = '/cable'
As a result, I run a project of this command:
rails server -b SERVER_IP -p 3020
This error is displayed in the console browser:
WebSocket connection to 'ws://site.com/cable' failed: Unexpected response code: 404
A piece of the log by running the project:
Started GET "/cable" for SERVER_IP at 2016-07-12 16:20:14 +0300
Cannot render console from SERVER_IP! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Started GET "/cable/" [WebSocket] for SERVER_IP at 2016-07-12 16:20:14 +0300
Request origin not allowed: example.com
Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)
Finished "/cable/" [WebSocket] for SERVER_IP at 2016-07-12 16:20:14 +0300
The error may be what? What am I doing wrong?
Definitions:
SERVER_IP - this disguised the original IP address of the server.
example.com - this disguised the original URL of the site.

Make sure you have added these lines in your development.rb file
config.action_cable.url = "ws://localhost:3000/cable"
config.action_cable.allowed_request_origins = [/http:\/\/*/,
/https:\/\/*/]

Related

Duplicated request info log in Rails 5 server only app

I have a Rails 5.2.3 application with Ruby 2.4.5.
I found a weird issue that the request info are logged twice in stdout.
Here is the log config in config/environments/product.rb
config.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))
config.log_tags = [ lambda {|req| "#{req.cookie_jar["_session_id"]}" }, :remote_ip, :uuid ]
Supposedly it will tag every log with the remote ip and request uuid, and it does for most of logs, except there is a weird additional log for the request. In following example, the last line is a duplicated log for the request without the tag:
[INFO] [2019-10-28 06:11:45 UTC] [127.0.0.1] [f6de1900-a7e5-4486-8b73-7095d0cacb35] Started GET "/api/v1/nodes?pageSize=20&pageNumber=1" for 127.0.0.1 at 2019-10-28 06:11:45 +0000
[INFO] [2019-10-28 06:11:45 UTC] [127.0.0.1] [f6de1900-a7e5-4486-8b73-7095d0cacb35] Processing by Api::V1::NodesController#index as XML
...
...
[INFO] [2019-10-28 06:20:02 UTC] [127.0.0.1] [993e0db4-3995-41ef-851a-bfea1bc25781] Completed 200 OK in 1084ms (Views: 341.9ms | ActiveRecord: 150.6ms)
127.0.0.1 - - [28/Oct/2019:06:20:02 +0000] "GET /api/v1/nodes?pageSize=20&pageNumber=1 HTTP/1.1" 200 - 1.1347
I checked configurations, there is no any other logger configured.
The consequence is that there is a timer in client side to check notification status by every 5 seconds. I added a log silencer to avoid log such request:
# config/application.rb
config.middleware.insert_before Rails::Rack::Logger, LogSilencer, silenced: /notification_messages/
# lib/log_silencer.rb
class LogSilencer
def initialize(app, opts = {})
#app = app
#silenced = opts.delete(:silenced)
end
def call(env)
if #silenced.match(env['PATH_INFO'])
Rails.logger.silence do
#app.call(env)
end
else
#app.call(env)
end
end
end
It does avoid logging from the tagged logger, but the duplicated request logs are still there, then the stdout is full of this request
127.0.0.1 - - [28/Oct/2019:07:04:21 +0000] "GET /api/v1/notification_messages/to_notify HTTP/1.1" 200 - 0.0118
127.0.0.1 - - [28/Oct/2019:07:04:26 +0000] "GET /api/v1/notification_messages/to_notify HTTP/1.1" 200 - 0.0140
127.0.0.1 - - [28/Oct/2019:07:04:31 +0000] "GET /api/v1/notification_messages/to_notify HTTP/1.1" 200 - 0.0137
127.0.0.1 - - [28/Oct/2019:07:04:36 +0000] "GET /api/v1/notification_messages/to_notify HTTP/1.1" 200 - 0.0149
...
Spent a whole day try to find out who generated this log, but no any clue...
Would like to ask for help on how to turn off this log so make the log data clear...
Thanks!
Seems the logs come from the web server used when up the Rails app.
When use WEBrick, the log is like
=> Booting WEBrick
=> Rails 5.2.3 application starting in development on http://localhost:4000
=> Run `rails server -h` for more startup options
[2019-10-30 07:01:13] INFO WEBrick 1.3.1
[2019-10-30 07:01:13] INFO ruby 2.4.5 (2018-10-18) [x86_64-linux]
[2019-10-30 07:01:13] INFO WEBrick::HTTPServer#start: pid=5812 port=4000
127.0.0.1 - - [30/Oct/2019:07:01:17 UTC] "GET /test HTTP/1.1" 304 0
- -> /test
When use unicorn, the log is like:
I, [2019-10-30T07:02:47.626962 #5956] INFO -- : Refreshing Gem list
I, [2019-10-30T07:02:48.289373 #5956] INFO -- : listening on addr=0.0.0.0:4000 fd=17
I, [2019-10-30T07:02:48.393598 #5956] INFO -- : master process ready
I, [2019-10-30T07:02:48.394853 #5965] INFO -- : worker=0 ready
I, [2019-10-30T07:02:48.399878 #5968] INFO -- : worker=1 ready
127.0.0.1 - - [30/Oct/2019:07:02:52 +0000] "GET /test HTTP/1.1" 304 - 0.0724
I can find that the request log format is a bit different (the time zone info, the time consumed etc).
I use Unicorn, its logger by default uses stderr, but seems the logger configuration does not work
logger Logger.new("#{rails_root}/log/unicorn.log")
so I have to set the stderr path
stderr_path "#{rails_root}/log/unicorn.stderr.log
Then the request logs are in the unicorn.stderr.log file, and STDOUT are the rails app logs.
But still dont know how to turn it off since it is a kind of duplicated and useless log...

Action cable direct connection (Expected HTTP 101 response but was '404 Not Found' + Failed to upgrade to WebSocket)

I'm trying to open a direct websocket connection to the route of my action cable. Unfortunately that's not working. I'm only getting this error when curling or just hitting http://localhost:3000/cable directly..
Started GET "/cable" for 127.0.0.1 at 2019-02-06 20:04:08 -0600
Started GET "/cable/"[non-WebSocket] for 127.0.0.1 at 2019-02-06 20:04:08 -0600
Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: keep-alive, HTTP_UPGRADE: )
Finished "/cable/"[non-WebSocket] for 127.0.0.1 at 2019-02-06 20:04:08 -0600
This is the exception in my client:
java.net.ProtocolException: Expected HTTP 101 response but was ‘404 Not Found’
But if I hit http://localhost:3000/page/index with a browser, I see the following output:
Started GET "/page/index" for 127.0.0.1 at 2019-02-06 20:05:30 -0600
Processing by PageController#index as HTML
Rendering page/index.html.erb within layouts/application
Rendered page/index.html.erb within layouts/application (0.3ms)
Completed 200 OK in 28ms (Views: 25.5ms | ActiveRecord: 0.0ms)
Started GET "/cable" for 127.0.0.1 at 2019-02-06 20:05:30 -0600
Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2019-02-06 20:05:30 -0600
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
User Load (0.7ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
↳ app/channels/application_cable/connection.rb:12
Registered connection (Z2lkOi8vd2hvcy1yZWFkeS1hcGkvVXNlci8z)
RoomChannel is transmitting the subscription confirmation
RoomChannel is streaming from room_channel
RoomChannel is transmitting the subscription confirmation
RoomChannel is streaming from room_channel
Here are the relevant files, let me know if I need to share more:
#routes.rb
Rails.application.routes.draw do
mount API::Base, at: '/'
mount ActionCable.server => '/cable/chat'
get 'page/index'
root 'page#index'
end
#page_controller.rb
class PageController < ApplicationController
def index
end
end
I'm trying to get a connection to the websocket simply by curling to the ActionCable server route. Is that possible?
The issue was that I was not sending an Origin header on the http request so allowed_request_origins couldnt match anything. Because of that, it was giving this super obscure error message about not being able to convert the http connection to a websocket one.

Log management on Docker

I want to send STDOUT log from Docker container to fluentd.
But, when one container outputs access logs and error logs, logs are mixed.
example
# rails access log
2017-04-07 12:10:01 +0000 6a51e389e724: {"log":"I, [2017-04-07T12:10:01.825923 #7] INFO -- : Started GET \"/users/new\" for 172.21.0.1 at 2017-04-07 12:10:01 +0000","container_id":"6a51e389e724c67be4e714402b69da192db4a304cbfdf638594de6cff9774c23","container_name":"/app","source":"stdout"}
# rails error log
2017-04-07 12:10:01 +0000 6a51e389e724: {"container_id":"6a51e389e724c67be4e714402b69da192db4a304cbfdf638594de6cff9774c23","container_name":"/app","source":"stdout","log":"E, [2017-04-07T12:10:01.830039 #7] ERROR -- : Invoke logger error"}
# rails access log
2017-04-07 12:10:03 +0000 6a51e389e724: {"log":"I, [2017-04-07T12:10:01.825923 #7] INFO -- : Started POST \"/users/create\" for 172.21.0.1 at 2017-04-07 12:10:01 +0000","container_id":"6a51e389e724c67be4e714402b69da192db4a304cbfdf638594de6cff9774c23","container_name":"/app","source":"stdout"}
Can I add a label for each log type?
Please tell me if you have a good solution.
Thanks you and best regards.
As your app's access and error logs are sent to STDOUT of container, then you have no way to separate them by logging driver. As solution you can send access log to STDOUT, error log to STDERR of container, then later differentiate logs by "source" field of each json message (this can be done if you connect fluentd to elasticsearch+kibana).

Getting websocket error code 1006 when trying to connect to Actioncable server

I'm building an app using Nativescript/Angular 2 and I'm also using a javascript library to use websockets connecting it with an Actioncable Rails app.
When trying to establish connection I get a websocket error code 1006 on the Nativescript log console and the connection gets closed.
I noticed that the initial HTTP (the handshake) request sends two values for Sec-WebSocket-Protocol on the header (actioncable-v1-json, actioncable-unsupported) but the headers in the response have only one value for Sec-WebSocket-Protocol which is 'actioncable-v1-json' and 'actioncable-unsupported' is missing.
I believe this error happens because of the missing protocol in the response.
Does anyone know how to add this header (actioncable-unsupported) to the handshake response? Or any other ideas of what is causing this error?
There is no error in the rails log, it just gets connected and then disconnected:
Started GET "/v1/cable/" [WebSocket] for 192.168.1.8 at 2017-04-02 17:04:06 -0700
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)
Finished "/v1/cable/" [WebSocket] for 192.168.1.8 at 2017-04-02 17:04:06 -0700
The error message displayed on the Nativescript console is this:
CONSOLE LOG file:///app/tns_modules/nativescript-actioncable/lib/action_cable.js:46:33: [ActionCable] Opening WebSocket, current state is null, subprotocols: actioncable-v1-json,actioncable-unsupported 1491179483038
CONSOLE LOG file:///app/tns_modules/nativescript-actioncable/lib/action_cable.js:46:33: [ActionCable] ConnectionMonitor started. pollInterval = 3000 ms 1491179483042
CONSOLE LOG file:///app/tns_modules/nativescript-actioncable/lib/action_cable.js:46:33: [ActionCable] Socket was closed because: code: 1006 1491179483109
Thank you
I was having this issue and the issue was the cable.yml configuration.
We noticed that the staging environment had this value for url:
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
Removing that value and actually other values fixed it for us.
New cable.yml staging config:
staging:
adapter: redis
Working!

Can access production database from Rails console but not Rails App

When I try to login to my Devise app using the rails console on my production database, I can with no trouble, however I cannot when using my Rails App.
I launch my Rails Console with rails c -e production, from my home environment (not SSHing int it or anything) and then proceed to execute app.post('/users/sign_in', {"user"=>{"email"=>"email", "password"=>"password"}}), which succeeds with:
Started POST "/users/sign_in" for 127.0.0.1 at 2014-03-10 05:37:31 +0000
Started POST "/users/sign_in" for 127.0.0.1 at 2014-03-10 05:37:31 +0000
Processing by DeviseSessionsController#create as HTML
Processing by DeviseSessionsController#create as HTML
Parameters: {"user"=>{"email"=>"amar#sittr.co.nz", "password"=>"[FILTERED]"}}
Parameters: {"user"=>{"email"=>"amar#sittr.co.nz", "password"=>"[FILTERED]"}}
Redirected to http://www.example.com/dashboard
Redirected to http://www.example.com/dashboard
Completed 302 Found in 1830ms (ActiveRecord: 1426.3ms)
Completed 302 Found in 1830ms (ActiveRecord: 1426.3ms)
=> 302
From which I can then use app.get '/dashboard' which is a password protected page, and then succeeds with:
Started GET "/dashboard" for 127.0.0.1 at 2014-03-10 05:38:14 +0000
Started GET "/dashboard" for 127.0.0.1 at 2014-03-10 05:38:14 +0000
Processing by StaticPagesController#home as HTML
Processing by StaticPagesController#home as HTML
Rendered static_pages/home.html.haml within layouts/application (139.6ms)
Rendered static_pages/home.html.haml within layouts/application (139.6ms)
Completed 200 OK in 6370ms (Views: 686.2ms | ActiveRecord: 5087.6ms)
Completed 200 OK in 6370ms (Views: 686.2ms | ActiveRecord: 5087.6ms)
=> 200
This is all working as expected, except for when I try and go to the production site, and sign in with the same credentials, it gives me a 500 error Errno::ECONNREFUSEDdevise_sessions#create
Connection refused - connect(2) for "localhost" port 9200. What confuses me is that this says it is trying to connect to localhost which wouldn't make any sense. The following is my database.yml file (with the sensitive bits taken out):
production:
adapter: postgresql
database: db_name
pool: 5
timeout: 5000
host: rds.database.com
port: 5432
username: username
password: password
As you can see, I have set the port and host correctly. What am I doing wrong? Thanks in advance.

Resources