使用 Puma 和 Nginx 配置调试 Action Cable
Debug Action Cable with Puma and Nginx configuration
Action Cable 在开发中有效,但在生产中无效。我不知道如何调试它或如何缩小问题范围。在生产中,我在 Debian 9 系统上使用 puma (3.12.0)、Nginx (1.10.3)、Redis (3.2.6) 和 Rails 5.2.2 (Ruby 2.5.3p105)。除了 Action Cable 以外的所有东西都工作正常。
rails 生产日志以这些行结尾:
I, [...] INFO -- : [ae5f4486-eadd-466d-a4de-fd8db3cdcfb4] Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)
D, [...] DEBUG -- : ESC[1mESC[36mUser Load (0.8ms)ESC[0m ESC[1mESC[34mSELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ESC[0m [["LIMIT", 1]]
E, [...] ERROR -- : An unauthorized connection attempt was rejected
E, [...] ERROR -- : Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)
I, [...] INFO -- : Finished "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-14 15:52:53 +0100
I, [...] INFO -- : Finished "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-14 15:52:53 +0100
I, [...] INFO -- : [58aa5ff7-e440-4050-88b6-6e9dcdc691a0] Started GET "/cable" for 127.0.0.1 at 2019-01-14 15:55:35 +0100
I, [...] INFO -- : [58aa5ff7-e440-4050-88b6-6e9dcdc691a0] Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-14 15:55:35 +0100
I, [...] INFO -- : [58aa5ff7-e440-4050-88b6-6e9dcdc691a0] Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)
D, [...] DEBUG -- : ESC[1mESC[36mUser Load (0.8ms)ESC[0m ESC[1mESC[34mSELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ESC[0m [["LIMIT", 1]]
E, [...] ERROR -- : An unauthorized connection attempt was rejected
E, [...] ERROR -- : Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)
I, [...] INFO -- : Finished "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-14 15:55:35 +0100
I, [...] INFO -- : Finished "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-14 15:55:35 +0100
Nginx 配置:
upstream my_app {
server unix:/tmp/example.sock;
}
server {
listen 443 ssl;
# ... ssl configuration
server_name xyz.example.com;
root /var/www/example/current/public;
location /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location / {
try_files $uri @ruby;
}
location @ruby {
proxy_pass http://my_app;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Ssl on; # Optional
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Host $host;
proxy_redirect off;
}
location /cable {
proxy_pass http://my_app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
在 production.rb
我有这些行:
config.action_cable.url = 'wss://xyz.example.com/cable'
config.action_cable.disable_request_forgery_protection = true
app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
# This is a websocket so we have no warden and no session here
# How to reuse the login made with devise?
# http://www.rubytutorial.io/actioncable-devise-authentication/
self.current_user = find_verified_user
end
private
def find_verified_user
if verified_user = User.find_by(id: cookies.signed["user.id"])
verified_user
else
reject_unauthorized_connection
end
end
end
end
我在我的开发日志中没有看到 An unauthorized connection attempt was rejected
错误,所以我想这一定是问题所在。但是谷歌搜索该短语没有帮助。
如何缩小问题范围?
在我看来,ActionCable 部分可以正常工作,但存在身份验证错误。 Successfully upgraded to WebSocket
表示它打开了与用户的 websocket 连接,但是 An unauthorized connection attempt was rejected
表示您在代码中的某处拒绝了他们的连接。
检查你的 connection.rb
文件,你在某处调用 reject_unauthorized_connection
吗?
可能的修复
app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
end
protected
def find_verified_user
if current_user = env['warden'].user
current_user
else
reject_unauthorized_connection
end
end
end
end
Action Cable 在开发中有效,但在生产中无效。我不知道如何调试它或如何缩小问题范围。在生产中,我在 Debian 9 系统上使用 puma (3.12.0)、Nginx (1.10.3)、Redis (3.2.6) 和 Rails 5.2.2 (Ruby 2.5.3p105)。除了 Action Cable 以外的所有东西都工作正常。
rails 生产日志以这些行结尾:
I, [...] INFO -- : [ae5f4486-eadd-466d-a4de-fd8db3cdcfb4] Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)
D, [...] DEBUG -- : ESC[1mESC[36mUser Load (0.8ms)ESC[0m ESC[1mESC[34mSELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ESC[0m [["LIMIT", 1]]
E, [...] ERROR -- : An unauthorized connection attempt was rejected
E, [...] ERROR -- : Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)
I, [...] INFO -- : Finished "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-14 15:52:53 +0100
I, [...] INFO -- : Finished "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-14 15:52:53 +0100
I, [...] INFO -- : [58aa5ff7-e440-4050-88b6-6e9dcdc691a0] Started GET "/cable" for 127.0.0.1 at 2019-01-14 15:55:35 +0100
I, [...] INFO -- : [58aa5ff7-e440-4050-88b6-6e9dcdc691a0] Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-14 15:55:35 +0100
I, [...] INFO -- : [58aa5ff7-e440-4050-88b6-6e9dcdc691a0] Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)
D, [...] DEBUG -- : ESC[1mESC[36mUser Load (0.8ms)ESC[0m ESC[1mESC[34mSELECT "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT ESC[0m [["LIMIT", 1]]
E, [...] ERROR -- : An unauthorized connection attempt was rejected
E, [...] ERROR -- : Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: upgrade, HTTP_UPGRADE: websocket)
I, [...] INFO -- : Finished "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-14 15:55:35 +0100
I, [...] INFO -- : Finished "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-14 15:55:35 +0100
Nginx 配置:
upstream my_app {
server unix:/tmp/example.sock;
}
server {
listen 443 ssl;
# ... ssl configuration
server_name xyz.example.com;
root /var/www/example/current/public;
location /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location / {
try_files $uri @ruby;
}
location @ruby {
proxy_pass http://my_app;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Ssl on; # Optional
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Host $host;
proxy_redirect off;
}
location /cable {
proxy_pass http://my_app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
在 production.rb
我有这些行:
config.action_cable.url = 'wss://xyz.example.com/cable'
config.action_cable.disable_request_forgery_protection = true
app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
# This is a websocket so we have no warden and no session here
# How to reuse the login made with devise?
# http://www.rubytutorial.io/actioncable-devise-authentication/
self.current_user = find_verified_user
end
private
def find_verified_user
if verified_user = User.find_by(id: cookies.signed["user.id"])
verified_user
else
reject_unauthorized_connection
end
end
end
end
我在我的开发日志中没有看到 An unauthorized connection attempt was rejected
错误,所以我想这一定是问题所在。但是谷歌搜索该短语没有帮助。
如何缩小问题范围?
在我看来,ActionCable 部分可以正常工作,但存在身份验证错误。 Successfully upgraded to WebSocket
表示它打开了与用户的 websocket 连接,但是 An unauthorized connection attempt was rejected
表示您在代码中的某处拒绝了他们的连接。
检查你的 connection.rb
文件,你在某处调用 reject_unauthorized_connection
吗?
可能的修复
app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
end
protected
def find_verified_user
if current_user = env['warden'].user
current_user
else
reject_unauthorized_connection
end
end
end
end