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

5

有一个 Laravel/Vue.JS 应用程序托管在 AWS 后面的经典负载均衡器 (弹性 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;
}

现在,长轮询模式可以正常工作,但无法启动升级:

WebSocket 连接到 'wss://example.com/socket.io/?EIO=3&transport=websocket&sid=HmDFtq-aj1WgfGUyAAAJ' 失败: WebSocket 握手期间出错:响应码不正确:400

附注:在 Chrome 的 Frames 选项卡中,我只能看到这个奇怪的消息:(Opcode -1)

有人在 AWS Elastic Beanstalk 环境下成功使用 socket.io 吗?我浪费了两个星期处理这个问题,非常感谢任何建议或想法。谢谢!

更新。我打开了详细日志记录,并查看了 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; 并测试。 - Tarun Lalwani
你在 6001 套接字服务器日志中看到了什么? - Tarun Lalwani
据我了解,WSS请求甚至没有到达nginx,它被负载均衡器或其他东西阻止了... - Serhii Matrunchyk
经典型ELB不支持Websockets。 - Michael - sqlbot
@Michael-sqlbot 嗯。那么应该如何使用什么呢? - Serhii Matrunchyk
显示剩余4条评论
4个回答

11

您的ELB使用HTTP/HTTP监听器还是TCP/SSL监听器?Websockets只适用于后者协议类型。将监听器更改为TCP即可使其工作。

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


谢谢,我会尝试并很快回来。我想我之前尝试过,但我会再试一次。 - Serhii Matrunchyk
很酷,看起来它正在工作,但是我有一个实例(我有两个)出现了400错误。你的方法适用于多个实例吗? - Serhii Matrunchyk
是的,但在ELB上,您需要启用“粘性会话”或禁用“跨区域负载平衡”。目的是确保HTTP和websocket请求都发送到同一实例。我没有设置测试用例来证明它是否有效,但如果有效,请告诉我,我会更新答案。 - Steve E.
粘性会话无法应用于TCP/SSL层,仅适用于HTTP(S)。禁用跨区域负载平衡听起来不是一个好的解决方案,不是吗? - Serhii Matrunchyk
是否需要额外配置ProxyProtocol? - Serhii Matrunchyk
非常感谢您,先生。我花了一周的时间解决这个问题。您的答案帮了我很多。 - Adeel Imran

2

另一个选择是只使用新的应用程序负载均衡器,但这在运行elasticbeanstalk时默认情况下不会出现

可以创建一个新环境来使用新类型,或尝试将经典负载均衡器迁移到应用程序(我是通过重新创建来实现的)

一旦创建,请添加一个用于端口443 HTTPS的监听器,一切都可以直接使用。

Chris


0
我曾经遇到过同样的问题,后端部署在AWS Elastic Beanstalk上,我们设置了负载均衡器来处理多个请求调用,从而解决了这个错误。因此,我认为您需要在Amazon Elastic Beanstalk中配置负载均衡器。同时,将您的EC2实例RAM更改为2GB+或t2.large。

-1

尝试在您的ElasticBeanstalk“软件”配置中将Apache代理服务器切换为Nginx。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接