ActionCable 在生产中不起作用。在开发中效果很好,但在生产中效果不佳。
在 Ubuntu 14.04 上使用 Puma 运行 Nginx。我已检查 redis-server 是否已启动并正在运行。
Rails-v 5.0.0.1
production.log
:
INFO -- : Started GET "/cable/"[non-WebSocket] for 178.213.184.193 at 2016-11-25 14:55:39 +0100
ERROR -- : Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: close, HTTP_UPGRADE: )
INFO -- : Finished "/cable/"[non-WebSocket] for 178.213.184.193 at 2016-11-25 14:55:39 +0100
客户要求:
GET ws://mityakoval.com/cable HTTP/1.1
Host: mityakoval.com
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://mityakoval.com
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4,uk;q=0.2,nb;q=0.2
Cookie: _vaktdagboka_session=******
Sec-WebSocket-Key: *******
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Protocol: actioncable-v1-json, actioncable-unsupported
回应:
HTTP/1.1 404 Not Found
Server: nginx/1.4.6 (Ubuntu)
Date: Fri, 25 Nov 2016 13:52:21 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-cache
X-Request-Id: d6374238-69ef-476e-8fc5-e2f8bbb663de
X-Runtime: 0.002500
nginx.conf
:
upstream puma {
server unix:///home/mityakoval/apps/vaktdagboka/shared/tmp/sockets/vaktdagboka-puma.sock;
}
server {
listen 80 default_server deferred;
# server_name example.com;
root /home/mityakoval/apps/vaktdagboka/current/public;
access_log /home/mityakoval/apps/vaktdagboka/current/log/nginx.access.log;
error_log /home/mityakoval/apps/vaktdagboka/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @puma;
location @puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
location /cable {
proxy_pass http://puma;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
error_page 500 502 503 504 /500.html;
client_max_body_size 10M;
keepalive_timeout 10;
}
cable.yml
:
redis: &redis
adapter: redis
url: redis://127.0.0.1:6379
production: *redis
development:
adapter: async
test:
adapter: async
在
production.rb
:
config.action_cable.allowed_request_origins = ["http://mityakoval.com"]
在
routes.rb
:
mount ActionCable.server, at: '/cable'
更新:
不要忘记重新启动 nginx :) 这对我来说就是问题。
您应该将
proxy_pass
属性的值从 http://puma
更改为 http://puma/cable
。
因此,
location
的正确 /cable
部分将是:
location /cable {
proxy_pass http://puma/cable;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
虽然其他帖子已经正确发布了解决方案,但我想我应该发布更多关于如何识别问题所在/在哪里为其他 nginx 新手修复问题的信息。
如果 Rails 错误包含
proxy_set_header Upgrade
,您就会知道您的 nginx 配置需要在安装操作电缆的路径上使用 HTTP_UPGRADE:
。 (意味着没有任何内容传递给 HTTP_UPGRADE)。解决问题后,我的日志显示 HTTP_UPGRADE: websocket
问题 1:正如操作中提到的,确保在进行更改后重新启动 nginx(我错误地这样做了)。
问题 2:还要在 nginx 配置中查找包含语句,因为您的配置可能会拆分到多个文件中。
location /cable {
部分应该位于 server {
内部,在我的情况下,它丢失了,因为它位于与包含语句不同的配置文件中,我有一段时间没有注意到。类似的错误但不同的问题:您的rails日志将在OP提到的不允许来源的错误之前的日志中包含一个额外的错误,即当您的rails配置需要更新时,因为另一个答案提到了更新配置。 action_cable.allowed_request_origins。
日志记录可能会随着 Rails 的变化而变化,但希望这有助于澄清问题所在以及我作为一个对 nginx 一无所知的人遇到的一些问题。
解决方案需要更改 NGINX 配置以接受此操作电缆请求。
location / {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
将上述行添加到 nginx 站点配置中的位置块,然后重新启动 nginx。
这次对话已经太晚了,但是,对于使用 Rails5、Action Cable 等遇到相同错误消息的任何人 & DEVISE,您只需按照here 的建议解决即可。这一切都归结为 Web 套接字服务器没有会话,因此出现错误消息。
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
logger.add_tags 'ActionCable', current_user.name
end
protected
def find_verified_user
verified_user = User.find_by(id: cookies.signed['user.id'])
if verified_user && cookies.signed['user.expires_at'] > Time.now
verified_user
else
reject_unauthorized_connection
end
end
end
end
Warden::Manager.after_set_user do |user,auth,opts|
scope = opts[:scope]
auth.cookies.signed["#{scope}.id"] = user.id
auth.cookies.signed["#{scope}.expires_at"] = 30.minutes.from_now
end
Warden::Manager.before_logout do |user, auth, opts|
scope = opts[:scope]
auth.cookies.signed["#{scope}.id"] = nil
auth.cookies.signed["#{scope}.expires_at"] = nil
end
解决方案由 Greg Molnar 开发
我的解决方案是将这些行添加到我的
production.rb
文件中:
config.action_cable.url = 'ws://your_site.com/your_action_cable'
config.action_cable.allowed_request_origins = [ 'http://your_site.com' ]
您可以更改 nginx 配置
/cable
proxy_set_header X-Forwarded-Proto http;
我使用了你的 nginx 配置并在 myu 服务器上添加了此更改,它工作正常。
合作过:
location ^~ /cable {
...
}
位置需要
^~
我正在使用 ws://app-url.com/cable
我使用了这个网址,它有效,(尽管我已经禁用了电缆的 ssl) wss://app-url.com/cable
使用 Rails 7.0.6 和 puma 6.4.0,这对我有用。
# .platform/nginx/conf.d/websocket.conf
server {
listen 80;
server_name yourdomain.com # || elastic.beanstalk.domain.com;
location /cable {
proxy_pass http://unix:///var/run/puma/my_app.sock;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-NginX-Proxy true;
proxy_redirect off;
}
}
在 config/environments/staging.rb 中
config.action_cable.url = wss://api.yourdomain.com/cable
config.action_cable.allowed_request_origins = [https://yourdomain.com]
config.action_cable.disable_request_forgery_protection = true # optional
在配置/puma.rb中
bind 'unix:///var/run/puma/my_app.sock'
在Procfile中
web: bundle exec puma -C config/puma.rb
worker: bundle exec sidekiq -c 1 -v
您的cable.yml 文件应如下所示:
production:
adapter: redis
url: <%=ENV['REDIS_URL']%>
然后你应该在环境中设置这个密钥,应该看起来像这样:
REDIS_URL: 'redis://redistogo:keyblahblahblhblah'
另外,你应该在生产环境中使用它。rb:
config.web_socket_server_url = "wss://YOUR_URL.com/cable"