尝试实现 socket.io 通信时收到 GET 400。 Node.js、ELB、Route 53、CloudFront 和 s3
Posted
技术标签:
【中文标题】尝试实现 socket.io 通信时收到 GET 400。 Node.js、ELB、Route 53、CloudFront 和 s3【英文标题】:Receiving GET 400 when trying to implement socket.io communication. Node.js, ELB, Route 53, CloudFront, and s3 【发布时间】:2021-01-05 21:26:36 【问题描述】:注意**我可以通过使用 route-53 和弹性 beanstalk 环境将 cloudfront 从 server.com 域的图片中移除来使事情正常运行。仍然很高兴知道为什么云端会阻止这一点,但不是直接关注开发**
我正在使用 cloudfront 和路由 53 为来自 s3 存储桶的 node.js 静态 socket.io 客户端提供服务。我正在尝试让该客户端使用弹性 beanstalk 与 node.js Web 服务器通信。网络服务器使用路由 53 域和云端与亚马逊证书管理器生成的 ssl 连接。
使用 http 客户端并直接连接到 beanstalk 环境,我看到了所需的功能。但是,当我尝试使用收到的客户端和服务器迁移到 SSL/https 时:
(log from /var/log/nginx/error.log on elastic beanstalk instance)
"GET /socket.io/ HTTP/1.1" 400 51 "-" "Amazon CloudFront"
这是从静态 s3 https 域运行的客户端代码:
import ioClient from "socket.io-client";
const ENDPOINT = "https://server.com";
export const socket = ioClient(ENDPOINT);
这里是服务器端。 process.env.port 设置为 8080,我可以通过弹性 beanstalk 日志验证应用正在侦听 8080。
const express = require("express");
const http = require("http");
const socket_io = require("socket.io");
const index = require("./routes/index");
const app = express();
app.use(index);
const server = http.createServer(app);
const io = socket_io(server);
const port = process.env.port || 4001;
server.listen(port, () => console.log(`http server listing on port $port`));
在 ALB 内部,我在端口 443 上设置了一个 https 侦听器,并通过 Amazon Certificate Manager (ACM) ssl 认证。侦听器有一个将 443 https 映射到 http 上的 8080 的进程,我认为 ngnix 应该从那里充当我在 8080 上的 socket.io 侦听器的反向代理
监听器和处理器
在我的节点项目文件夹的根目录中,我有一个 .ebextensions 目录,其中有一个名为 01_files.config 的文件,其中包含以下内容:
files:
"/etc/nginx/conf.d/websocketupgrade.conf" :
mode: "000755"
owner: root
group: root
content: |
proxy_pass http://localhost:8080;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header Host $host;
来自这篇帖子中的 cmets:socket.io handshake return error "Transport unknown" 我发现了以下 socket.io 错误代码
engine.io message type:
open =0
close =1
ping =2
pong =3
message =4
upgrade =5
noop =6
socket.io message type:
connect = 0
disconnect = 1
event = 2
ack = 3
error = 4
binary_event = 5
binary_ack = 6
所以,400 51 可能意味着“错误请求,升级断开连接。”
这是响应正文:
"code":0,"message":"Transport unknown"
这是浏览器中客户端应用程序的错误:
polling-xhr.js:268 GET https://server.com/socket.io/?EIO=3&transport=polling&t=NIgQkyr 400
这看起来像是 xhr 传输层上的失败轮询请求
【问题讨论】:
【参考方案1】:从 AWS 支持收到此解决方案:
我已经与 CloudFront (CF) 专家讨论了您的案例,并且我已经 给你一些信息。
在与我的同事完成 CF 设置后,我们注意到 CF 不会将 HOST 标头转发到 Elastic Beanstalk (EB)。这 表示如果 CF 和 EB 之间的连接是通过 HTTPS 建立的, 它会失败。为了解决这个问题,我们必须看看 CF 政策。 我们注意到您正在使用缓存策略。在本政策中 有一个标题设置。在这里我建议你 指定主机设置。这样,它可以保护 HTTPS 连接 根据来源证明。
如果这不起作用,我可以提出其他建议。这 您看到的错误 (GET /socket.io/ HTTP/1.1" 400 51 "-" "Amazon CloudFront" "(redacted IP, redacted IP") 应该返回一个 “X-Amz-Cf-Id”ID 和一个值(类似于“X-Amz-Cf-Id: jkahDAKJSHDAjhAKSJDHasd==")。既然没有,我怀疑可能 websocket 请求参数出错了。为此我 建议查看我们的文档并确保 正在使用 CloudFront 所需的正确请求参数。你 可以在此处找到该文档的链接:[1]。
如果一切都失败了,我建议您向您的 CF 提出请求并 记录从响应头中返回的键值对 CF。它应该看起来像“X-Amz-Cf-Id: jkahDAKJSHDAjhAKSJDHasd==" (我提到的相同 ID 和值 较早)。这个值允许我们作为支持工程师拉 使用我们的工具的 CF 内部日志。这个值需要 在请求时记录。一旦你有了这个键值 对,然后您可以向 CloudFront 团队开具支持票证, 向他们提供错误详细信息以及键值对,以及 CF 工程师将非常乐意为您提供帮助。此外, 您甚至可以在新的案例中引用此案例(案例 ID = 7399701121) 案例,以便协助您的工程师了解更多背景信息。
总结一下,我的第一个建议是你转发主机 标题。二是使用请求所需的参数 云前。最后,如果您在那之后遇到另一个错误, 记录 CloudFront 为 错误。由于我不是 CloudFront 专家,我建议打开一个 新的 CloudFront 案例并在消息中提供该键值对。
我希望这些信息对您有用。如果你还有 有任何问题或疑虑,请随时与我们联系。
【讨论】:
嗨 Lucas,我们遇到了类似的问题。我们在 ec2 机器中有我们的套接字 io,而 s3 有我们的应用程序正在尝试建立连接。你能看看这里吗***.com/questions/66205150/…以上是关于尝试实现 socket.io 通信时收到 GET 400。 Node.js、ELB、Route 53、CloudFront 和 s3的主要内容,如果未能解决你的问题,请参考以下文章
Py修行路 socket + select 实现 异步IO模块