尝试实现 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
注意** 我能够通过仅使用 route-53 和弹性 beanstalk 环境将云端从 server.com 域的图片中移除,从而使事情变得可操作。仍然很高兴知道为什么 cloudfront 会阻止它,但不是开发的直接问题 **
我正在使用 cloudfront 和路由 53 为一个 node.js 静态 socket.io 客户端提供一个 s3 存储桶。我试图让这个客户端与一个 node.js 网络服务器使用弹性豆茎。网络服务器使用 route 53 域和 cloudfront 与亚马逊证书管理器生成的 ssl 连接。
使用 http 客户端并直接连接到 beantalk 环境,我看到了所需的功能。但是,当我尝试使用收到的客户端和服务器移动到 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,我可以通过 elastic 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 应该从那里充当我的 socket.io 8080
侦听器的反向代理
监听器和处理器
在我的节点项目文件夹的根目录中,我有一个 .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;
从 post 中的评论: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 传输层上的失败轮询请求
从 AWS 支持收到此解决方案:
I have discussed your case with a CloudFront (CF) expert and I have
some information for you.
After going through the CF setup with my colleague, we noticed that CF
is not forwarding the HOST header to Elastic Beanstalk (EB). This
means if the connection between CF and EB is established over HTTPS,
it will fail. To fix this, we had to take a look at the CF policies.
We noticed that you are making use of Cache Policies. In this policy
there is a setting for Headers. Here I would recommend that you
specify the HOST setting. This way, it secures the HTTPS connection
against the Origins certificated.
If that does not work, there is something else I could suggest. The
error you were seeing (GET /socket.io/ HTTP/1.1" 400 51 "-" "Amazon
CloudFront" "(redacted IP, redacted IP") should have returned an
"X-Amz-Cf-Id" ID along with a value (something like "X-Amz-Cf-Id:
jkahDAKJSHDAjhAKSJDHasd=="). Since it did not, I suspect something may
have gone wrong with the websocket request parameters. For this I
would recommend taking a look at our documentation and ensure that the
correct request parameters required for CloudFront are being used. You
can find a link to that documentation here: [1].
If all else fails, I would recommend making a request to your CF and
record the key-value pair that is returned in the response header from
CF. It should look something like "X-Amz-Cf-Id:
jkahDAKJSHDAjhAKSJDHasd==" (the same ID and value I mentioned
earlier). This value allows us as support engineers to pull the
internal logs for CF using our tooling. This value will need to be
recorded at the time of the request. Once you have this key-value
pair, you can then open a support ticket with the CloudFront team,
provide them with the error details as well as the key-value pair, and
a CF engineer would be more than happy to assist you. Additionally,
you could even reference this case (case ID = 7399701121) on the new
case so that the engineer assisting you can have some more context.
To sum up, my first recommendation is that you forward the host
header. Second is to use the request parameters required for
CloudFront. And last, if you encounter another error after that,
record the value from the HTTP response given by CloudFront for the
error. Since I am not a CloudFront expert, I would suggest opening a
new CloudFront case and providing that key-value pair in the message.
I hope you find this information useful. If you have any more
questions or concerns, please feel free to reach out.
注意** 我能够通过仅使用 route-53 和弹性 beanstalk 环境将云端从 server.com 域的图片中移除,从而使事情变得可操作。仍然很高兴知道为什么 cloudfront 会阻止它,但不是开发的直接问题 **
我正在使用 cloudfront 和路由 53 为一个 node.js 静态 socket.io 客户端提供一个 s3 存储桶。我试图让这个客户端与一个 node.js 网络服务器使用弹性豆茎。网络服务器使用 route 53 域和 cloudfront 与亚马逊证书管理器生成的 ssl 连接。
使用 http 客户端并直接连接到 beantalk 环境,我看到了所需的功能。但是,当我尝试使用收到的客户端和服务器移动到 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,我可以通过 elastic 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 应该从那里充当我的 socket.io 8080
侦听器的反向代理监听器和处理器
在我的节点项目文件夹的根目录中,我有一个 .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;
从 post 中的评论: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 传输层上的失败轮询请求
从 AWS 支持收到此解决方案:
I have discussed your case with a CloudFront (CF) expert and I have some information for you.
After going through the CF setup with my colleague, we noticed that CF is not forwarding the HOST header to Elastic Beanstalk (EB). This means if the connection between CF and EB is established over HTTPS, it will fail. To fix this, we had to take a look at the CF policies. We noticed that you are making use of Cache Policies. In this policy there is a setting for Headers. Here I would recommend that you specify the HOST setting. This way, it secures the HTTPS connection against the Origins certificated.
If that does not work, there is something else I could suggest. The error you were seeing (GET /socket.io/ HTTP/1.1" 400 51 "-" "Amazon CloudFront" "(redacted IP, redacted IP") should have returned an "X-Amz-Cf-Id" ID along with a value (something like "X-Amz-Cf-Id: jkahDAKJSHDAjhAKSJDHasd=="). Since it did not, I suspect something may have gone wrong with the websocket request parameters. For this I would recommend taking a look at our documentation and ensure that the correct request parameters required for CloudFront are being used. You can find a link to that documentation here: [1].
If all else fails, I would recommend making a request to your CF and record the key-value pair that is returned in the response header from CF. It should look something like "X-Amz-Cf-Id: jkahDAKJSHDAjhAKSJDHasd==" (the same ID and value I mentioned earlier). This value allows us as support engineers to pull the internal logs for CF using our tooling. This value will need to be recorded at the time of the request. Once you have this key-value pair, you can then open a support ticket with the CloudFront team, provide them with the error details as well as the key-value pair, and a CF engineer would be more than happy to assist you. Additionally, you could even reference this case (case ID = 7399701121) on the new case so that the engineer assisting you can have some more context.
To sum up, my first recommendation is that you forward the host header. Second is to use the request parameters required for CloudFront. And last, if you encounter another error after that, record the value from the HTTP response given by CloudFront for the error. Since I am not a CloudFront expert, I would suggest opening a new CloudFront case and providing that key-value pair in the message.
I hope you find this information useful. If you have any more questions or concerns, please feel free to reach out.