ActionCable - WebSocket 握手期间出错:意外响应代码:404 [英] ActionCable - Error during WebSocket handshake: Unexpected response code: 404

查看:199
本文介绍了ActionCable - WebSocket 握手期间出错:意外响应代码:404的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

已通过 Capistrano 部署了我的 Rails 5.2 应用程序,但我在使用 ActionCable 时遇到了问题.我正在使用 Nginx、Puma 和 Lets Encrypt.

我尝试了多种配置组合,但每次都收到相同的错误.我不确定如何调试这个问题,建议以及重新安排我的 ngnx.conf 的任何提示都会很受欢迎.

已将真实网站更改为 website.com

nginx.conf

上游美洲狮{服务器 unix:///home/deploy/apps/website/shared/tmp/sockets/website-puma.sock;}服务器 {server_name website.com www.website.com;root/home/deploy/apps/website/current/public;索引 index.html;位置 ^~/assets/{gzip_static 开启;最大到期;add_header 缓存控制公共;}try_files $uri/index.html $uri @puma;位置@puma {proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header 主机 $http_host;proxy_redirect 关闭;proxy_pass http://puma;}位置/电缆{proxy_pass http://puma;proxy_http_version 1.1;proxy_set_header 升级 websocket;proxy_set_header 连接升级;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}error_page 500 502 503 504/500.html;client_max_body_size 10M;keepalive_timeout 10;听 [::]:443 ssl ipv6only=on;# 由 Certbot 管理听 443 ssl;# 由 Certbot 管理ssl_certificate/etc/letsencrypt/live/website.com/fullchain.pem;# 由 Certbot 管理ssl_certificate_key/etc/letsencrypt/live/website.com/privkey.pem;# 由 Certbot 管理包括/etc/letsencrypt/options-ssl-nginx.conf;# 由 Certbot 管理ssl_dhparam/etc/letsencrypt/ssl-dhparams.pem;# 由 Certbot 管理}服务器 {如果($host = www.website.com){返回 301 https://$host$request_uri;} # 由 Certbot 管理如果($host = website.com){返回 301 https://$host$request_uri;} # 由 Certbot 管理听 80 default_server;听 [::]:80 default_server ipv6only=on;server_name website.com www.website.com;返回404;# 由 Certbot 管理}

config/production.rb

 config.action_cable.mount_path = '/cable'config.action_cable.url = 'wss://website.com/cable'config.action_cable.allowed_request_origins = ['https://website.com', 'http://website.com']

错误信息

评论帖子

更新

更新了 nginx.conf

上游美洲狮{服务器 unix:///home/deploy/apps/immersive/shared/tmp/sockets/immersive-puma.sock;}服务器 {如果($host = www.immersive.ch){返回 301 https://$host$request_uri;} # 由 Certbot 管理如果($host = immersive.ch){返回 301 https://$host$request_uri;} # 由 Certbot 管理听 80 default_server;听 [::]:80 default_server ipv6only=on;server_name immersive.ch www.immersive.ch;返回404;# 由 Certbot 管理}服务器 {server_name immersive.ch www.immersive.ch;root/home/deploy/apps/immersive/current/public;索引 index.html;位置 ^~/assets/{gzip_static 开启;最大到期;add_header 缓存控制公共;}try_files $uri/index.html $uri @puma;位置@puma {proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header 主机 $http_host;proxy_redirect 关闭;proxy_pass http://puma;}位置/电缆{proxy_pass http://puma;proxy_http_version 1.1;proxy_set_header 升级 $http_upgrade;proxy_set_header 连接升级";proxy_set_header 主机 $host;proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass_request_headers 开启;代理缓冲关闭;proxy_redirect 关闭;休息;}error_page 500 502 503 504/500.html;client_max_body_size 10M;keepalive_timeout 10;听 [::]:443 ssl ipv6only=on;# 由 Certbot 管理听 443 ssl;# 由 Certbot 管理ssl_certificate/etc/letsencrypt/live/immersive.ch/fullchain.pem;# 由 Certbot 管理ssl_certificate_key/etc/letsencrypt/live/immersive.ch/privkey.pem;# 由 Certbot 管理包括/etc/letsencrypt/options-ssl-nginx.conf;# 由 Certbot 管理ssl_dhparam/etc/letsencrypt/ssl-dhparams.pem;# 由 Certbot 管理}

生产.rb

config.action_cable.mount_path = '/cable'config.action_cable.url = 'wss://immersive.ch/cable'config.action_cable.allow_same_origin_as_host = trueconfig.action_cable.allowed_request_origins = ['*']#config.action_cable.allowed_request_origins = [ 'https://immersive.ch', 'http://immersive.ch' ]

curl 的部分输出

<代码>>获取/电缆 HTTP/1.1>主持人:immersive.ch>用户代理:curl/7.54.0>接受: */*>来源:https://immersive.ch>Sec-WebSocket-Key:MIN4DsiwEautsE11kgG5rg==>升级:websocket>连接:升级>Sec-WebSocket-版本:13><未找到 HTTP/1.1 404<服务器:nginx/1.15.5 (Ubuntu)<日期:2019 年 4 月 16 日,星期二 20:10:43 GMT<内容类型:文本/纯文本<传输编码:分块<连接:保持连接<缓存控制:无缓存<X 请求 ID:7a9aa8f1-676d-419b-9e4f-0c1bb38bcaa2<X 运行时间:0.004730<* 与主机 immersive.ch 的连接 #0 保持不变找不到网页%

美洲狮.rb

threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i线程threads_count,threads_count端口 ENV.fetch("PORT") { 3000 }环境 ENV.fetch("RAILS_ENV") { "development" }工人 2守护真插件:tmp_restart

编辑 2

/var/logs/nginx/access.log

HTTP/1.1" 200 4447 "https://immersive.ch/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"xxx.xxx.xxx.xxx - - [16/Apr/2019:22:33:58 +0200] "GET/cable HTTP/1.1" 404 24 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"xxx.xxx.xxx.xxx - - [16/Apr/2019:22:33:59 +0200] "GET/cable HTTP/1.1" 404 24 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"

puma.error.log

I, [2019-04-16T22:39:06.100106 #21136] INFO -- : [80dc2a43-13e1-499e-a8f6-9fd54d48270b] 开始 GET "/cable.xxx" for xxx.xxx.在 2019-04-16 22:39:06 +0200I, [2019-04-16T22:39:06.103811 #21136] INFO -- : [80dc2a43-13e1-499e-a8f6-9fd54d48270b] 开始 GET "/cable/"[non-WebSocket.xxx] for.xxx在 2019-04-16 22:39E, [2019-04-16T22:39:06.103943 #21136] ERROR -- : [80dc2a43-13e1-499e-a8f6-9fd54d48270b] 无法升级到 WebSocket (REQUEST_METHOD: UPGRATE, HTTP_CON: 关闭)I, [2019-04-16T22:39:06.104062 #21136] INFO -- : [80dc2a43-13e1-499e-a8f6-9fd54d48270b] 完成了/cable/"[non-WebSocket.xxx.xxx.xxx].2019-04-16 22:39

puma.access.log

2019-04-16 20:58: HTTP 解析错误,请求格式错误(127.0.0.1):#<Puma::HttpParserError: Invalid HTTP format, parsing failed.>

解决方案

ActionCable 在 Origin 标头丢失或不匹配/无效时回答 404.

检查这不是您经常遇到的 404:

curl -v 'https://your_site.com/cable' -H '来源:https://your_site.com' -H 'Sec-WebSocket-Key:MIN4DsiwEAutsE11kgG5rg==' -H '升级: websocket' -H '连接:升级' -H 'Sec-WebSocket-Version: 13'

当一切正常时,会出现 HTTP/1.1 101 Switching Protocols,在来源不匹配时 - 只是 Page not found 正文,或者您的常规 404 页面(如果有的话)其他路由问题.

确保设置中的 allowed_request_origins 正确.请注意,它包括端口,如果它是非标准的.检查哪个 Origin 浏览器发送到 devtools

还有 config.action_cable.allow_same_origin_as_host = true(默认情况下,需要正确的 HostX-Forwarded-Proto 标头)

然后我们需要 nginx 来传递所有用于重建原点的标头:

 location/cable {proxy_pass http://puma;proxy_http_version 1.1;proxy_set_header 升级 $http_upgrade;proxy_set_header 连接升级";proxy_set_header 主机 $host;proxy_set_header X-Forwarded-Proto $scheme;# <- 很可能缺少这个proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass_request_headers 开启;# 这是默认的,但只是为了确定代理缓冲关闭;proxy_redirect 关闭;休息;}

更新:

activecable 响应的其余两种情况是连接身份验证失败和缺少 websocket 驱动程序(puma 不应该是这种情况)

Have deployed my Rails 5.2 app via Capistrano, and am having problems with ActionCable. I am using Nginx, Puma and Lets Encrypt.

I have tried many combinations of configuration, but each time am receiving the same error. I am not sure how to debug this issue, and suggestions as well and any tips on re-arranging my ngnx.conf would be well-appreciated.

Have changed the real website to website.com

nginx.conf

upstream puma {
  server unix:///home/deploy/apps/website/shared/tmp/sockets/website-puma.sock;
}

server {
  server_name website.com www.website.com;
  root /home/deploy/apps/website/current/public;
  index index.html;

  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 Upgrade websocket;
    proxy_set_header Connection Upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 10M;
  keepalive_timeout 10;

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/website.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/website.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    if ($host = www.website.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = website.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


  listen 80 default_server;
  listen [::]:80 default_server ipv6only=on;

  server_name website.com www.website.com;
    return 404; # managed by Certbot
}

config/production.rb

  config.action_cable.mount_path = '/cable'
  config.action_cable.url = 'wss://website.com/cable'
  config.action_cable.allowed_request_origins = [ 'https://website.com', 'http://website.com' ]

Error Message

Reviewed posts

UPDATE

Updated nginx.conf

upstream puma {
  server unix:///home/deploy/apps/immersive/shared/tmp/sockets/immersive-puma.sock;
}


  server {
    if ($host = www.immersive.ch) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = immersive.ch) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    server_name immersive.ch www.immersive.ch;
    return 404; # managed by Certbot
  }

  server {
    server_name immersive.ch www.immersive.ch;
    root /home/deploy/apps/immersive/current/public;
    index index.html;

    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 Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass_request_headers on;

      proxy_buffering off;
      proxy_redirect off;
      break;
    }

    error_page 500 502 503 504 /500.html;
    client_max_body_size 10M;
    keepalive_timeout 10;

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/immersive.ch/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/immersive.ch/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
  }

production.rb

config.action_cable.mount_path = '/cable'
config.action_cable.url = 'wss://immersive.ch/cable'
config.action_cable.allow_same_origin_as_host = true
config.action_cable.allowed_request_origins = [ '*' ]
#config.action_cable.allowed_request_origins = [ 'https://immersive.ch', 'http://immersive.ch' ]

Partial output of curl

> GET /cable HTTP/1.1
> Host: immersive.ch
> User-Agent: curl/7.54.0
> Accept: */*
> Origin: https://immersive.ch
> Sec-WebSocket-Key: MIN4DsiwEAutsE11kgG5rg==
> Upgrade: websocket
> Connection: Upgrade
> Sec-WebSocket-Version: 13
>
< HTTP/1.1 404 Not Found
< Server: nginx/1.15.5 (Ubuntu)
< Date: Tue, 16 Apr 2019 20:10:43 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Connection: keep-alive
< Cache-Control: no-cache
< X-Request-Id: 7a9aa8f1-676d-419b-9e4f-0c1bb38bcaa2
< X-Runtime: 0.004730
<
* Connection #0 to host immersive.ch left intact
Page not found%

puma.rb

threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
port        ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
workers 2
daemonize true
plugin :tmp_restart

EDIT 2

/var/logs/nginx/access.log

HTTP/1.1" 200 4447 "https://immersive.ch/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
xxx.xxx.xxx.xxx - - [16/Apr/2019:22:33:58 +0200] "GET /cable HTTP/1.1" 404 24 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"
xxx.xxx.xxx.xxx - - [16/Apr/2019:22:33:59 +0200] "GET /cable HTTP/1.1" 404 24 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"

puma.error.log

I, [2019-04-16T22:39:06.100106 #21136]  INFO -- : [80dc2a43-13e1-499e-a8f6-9fd54d48270b] Started GET "/cable" for xxx.xxx.xxx.xxx at 2019-04-16 22:39:06 +0200
I, [2019-04-16T22:39:06.103811 #21136]  INFO -- : [80dc2a43-13e1-499e-a8f6-9fd54d48270b] Started GET "/cable/"[non-WebSocket] for xxx.xxx.xxx.xxx at 2019-04-16 22:39
E, [2019-04-16T22:39:06.103943 #21136] ERROR -- : [80dc2a43-13e1-499e-a8f6-9fd54d48270b] Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: close, HTTP_UPGRADE: )
I, [2019-04-16T22:39:06.104062 #21136]  INFO -- : [80dc2a43-13e1-499e-a8f6-9fd54d48270b] Finished "/cable/"[non-WebSocket] for xxx.xxx.xxx.xxx at 2019-04-16 22:39

puma.access.log

2019-04-16 20:58: HTTP parse error, malformed request (127.0.0.1): #<Puma::HttpParserError: Invalid HTTP format, parsing fails.>

解决方案

ActionCable answers 404 when Origin header is missing or does not match/invalid.

Check that it's not you regular 404:

curl -v 'https://your_site.com/cable' -H 'Origin: https://your_site.com' -H 'Sec-WebSocket-Key: MIN4DsiwEAutsE11kgG5rg=='  -H 'Upgrade: websocket' -H 'Connection: Upgrade' -H 'Sec-WebSocket-Version: 13'

When everything is fine there'll be HTTP/1.1 101 Switching Protocols, on origin mismatch - just Page not found body, or your regular 404 page if there's some other routing trouble.

Make sure allowed_request_origins in settings is correct. Note that it includes port, if it's non-standard. Check which Origin browser sends in devtools

Also there's config.action_cable.allow_same_origin_as_host = true (the default, needs correct Host and X-Forwarded-Proto headers)

Then we need nginx to pass all the headers that are being used to reconstruct origin:

  location /cable {
    proxy_pass http://puma;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme; # <- most probably this one is missing
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass_request_headers on; # this is default, but just to be sure

    proxy_buffering off;
    proxy_redirect off;
    break;
  }

Update:

Remaining two cases when activecable responds with this is failed connection authentication and missing websocket driver(should not be the case for puma)

这篇关于ActionCable - WebSocket 握手期间出错:意外响应代码:404的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆