AWS EB:WebSocket 握手期间出错:意外响应代码:400

Posted

技术标签:

【中文标题】AWS EB:WebSocket 握手期间出错:意外响应代码:400【英文标题】:AWS EB: Error during WebSocket handshake: Unexpected response code: 400 【发布时间】:2018-02-23 19:21:38 【问题描述】:

有一个 Laravel/Vue.JS 应用程序托管在 AWS 上,位于 Classic Load Balancer (Elastic Beanstalk) 后面,并通过 nginx 在内部代理到 socket.io 服务器。 SSL 在 Nginx 上终止。

这是 nginx 配置:

location /socket.io 
    proxy_pass          http://127.0.0.1:6001;
    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-Real-IP         $remote_addr;
    proxy_set_header    X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header    X-Forwarded-Proto $scheme;

目前长轮询模式运行良好,但无法启动升级:

与“wss://example.com/socket.io/?EIO=3&transport=websocket&sid=HmDFtq-aj1WgfGUyAAAJ”的 WebSocket 连接失败:WebSocket 握手期间出错:意外响应代码:400

P.S Chrome 的Frames 标签我只能看到这条奇怪的消息:(Opcode -1)

是否有人成功让 socket.io 在 AWS Elastic Beanstalk 环境中工作?我只是浪费了两周的时间来处理这个问题,非常感谢任何建议或想法。谢谢!

更新。我打开了详细的日志记录,这里是 Nginx 中的变量:

$host example.com
$proxy_add_x_forwarded_for 134.xxx.xxx.xxx
$http_upgrade -
$remote_addr 172.31.10.208
$remote_user -
$server_name _
$upstream_addr 127.0.0.1:6001
$request GET /socket.io/?EIO=3&transport=polling&t=Lw26sYn&sid=6L5iHma-GJOeE3JQAAAX HTTP/1.1
$upstream_response_time 24.658 msec
$request_time 24.658

也许有人会发现其中一些值不正确,因此我将不胜感激。

【问题讨论】:

删除proxy_set_header Host $host;并测试 @TarunLalwani 不幸的是它不起作用。 您在6001 套接字服务器日志中看到了什么? 据我了解 WSS 请求甚至没有到达 nginx,它被 LoadBalancer 或其他东西阻止了...... 经典 ELB 不支持 websockets。 【参考方案1】:

您的 ELB 是使用 HTTP/HTTP 侦听器还是 TCP/SSL 侦听器? Websockets 仅适用于后一种协议类型。将监听器改为 TCP 即可。

或者,如果您使用 CLI 或 API 构建环境,您还可以使用应用程序负载均衡器 (ALB) 而不是传统负载均衡器 (ELB) 重建 ElasticBeanstalk 应用程序,因为 ALB 还支持 Websocket。此选项无法通过 Web 控制台使用。

【讨论】:

谢谢,我会试试,很快就会回来。我想我以前尝试过,但我会再试一次。 酷,它似乎工作正常,但我仍然有来自其中一个实例的 400 错误(我有两个)。您的方法是否适用于多个实例? 是的,但是在 ELB 上,您需要 enable sticky sessionsdisable cross-zone load balancing。目的是确保 HTTP 和 websocket 请求都发送到同一个实例。我没有测试用例设置来证明它有效,但如果有效,请告诉我,我会更新答案。 粘性会话不能应用于 TCP/SSL 层,仅适用于 HTTP(S)。而且禁用跨区域负载均衡听起来也不是一个好的解决方案,不是吗? 是否需要额外配置ProxyProtocol?【参考方案2】:

另一种选择是只使用在运行 elasticbeanstalk 时默认不会出现的新应用程序平衡器

可以使用新类型创建一个新环境或尝试将经典平衡器迁移到应用程序(我使用干净的重新创建)

创建后为端口 443 HTTPS 添加一个侦听器,一切都开箱即用。

克里斯

【讨论】:

【参考方案3】:

尝试在 ElasicBeanStalk“软件”配置中从 Apache 代理服务器切换到 Nginx。

【讨论】:

以上是关于AWS EB:WebSocket 握手期间出错:意外响应代码:400的主要内容,如果未能解决你的问题,请参考以下文章

Django:WebSocket 握手期间出错:意外的响应代码:500

WebSocket 连接失败。 WebSocket握手期间出错-socketjs

“WebSocket 握手期间出错:状态行无效”

WebSocket 握手期间出错:意外的响应代码:302

websocket失败:WebSocket握手期间出错:意外响应代码:400

WebSocket 握手期间出错:意外的响应代码:500