生产中的 Socket.io 返回 400 Bad Request 错误
Posted
技术标签:
【中文标题】生产中的 Socket.io 返回 400 Bad Request 错误【英文标题】:Socket.io in production returns 400 Bad Request error 【发布时间】:2021-08-11 14:06:24 【问题描述】:我在我的应用程序中使用 Socket.IO。 React 客户端使用socket.io-client4.1.3,Node.js 服务器使用socket.io4.1.3
在我本地机器上的开发环境中,一切正常。
React 应用程序在 http://localhost:3000 上运行,并使用以下方式连接到服务器:
import io from 'socket.io-client';
const socket = io('http://localhost:5000/');
Node.js 服务器配置如下:
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const cors = require('cors');
const io = require('socket.io')(server,
cors:
origin: 'http://localhost:3000'
,
maxHttpBufferSize: '1e6'
);
app.set('io', io);
app.use(express.static('public'));
app.use(express.json( limit: '7mb' ));
app.use(cors( origin: 'http://localhost:3000' ));
server.listen(5000, () => console.log('Server started'));
在生产中,我使用 Firebase 在子目录中托管 React 应用程序(例如 https://www.example.com/app/)。
在生产中,上面代码中的http://localhost:5000/和http://localhost:3000也分别改为https://app.example.com和https://www.example.com/app。
我的服务器使用 Ubuntu 20.04、nginx 和 Let's Encrypt,服务器块设置如下:
server
server_name app.example.com;
location /
proxy_pass http://localhost:5000/;
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/app.example.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 = app.example.com)
return 301 https://$host$request_uri;
# managed by Certbot
listen 80;
listen [::]:80;
server_name app.example.com;
return 404; # managed by Certbot
在 Google Chrome 中,我得到 No 'Access-Control-Allow-Origin' header is present on the requested resource 作为错误。在 Node.js 代码中将原点从 https://www.example.com/app 更改为 * 修复了这个问题。
但是,现在我的浏览器出现以下错误:
POST https://app.example.com/socket.io/?EIO=4&transport=polling&t=NirW_WK&sid=PmhwTyHRXOV4jWOdAAAF 400(错误请求)
为什么会这样?
谢谢
【问题讨论】:
能否请您在 nginx 中启用日志并将您看到的错误粘贴到那里? 另外,400 错误的响应正文是什么? 1.当您删除 cors 策略时会发生什么 2. 您可以尝试使用 webscoket 而不是 http 即。 ws://domainname 3. 在生产中我们可以连接本地主机吗? 在使用 let's encrypt 时,我发现 400 个错误请求错误有所增加。我相信这是向期望 HTTPS 加密流量的端点发出的纯 HTTP 请求之间的不匹配。我不是 100% 确定这是问题所在,但也许那里有你的线索,我会尝试首先删除由 certbot 管理的第二个server
部分,然后将重定向 301 的缓存从该块擦除到HTTPS 阻止。
【参考方案1】:
对 Node.js 和 Nginx 的一些小改动应该可以解决您的问题:
Node.js
首先,我建议您更改此设置:
cors:
origin: 'http://localhost:3000'
,
对此(指定here):
cors:
origin: 'http://localhost:3000',
methods: ["GET", "POST"]
,
Nginx
改变这个:
location /
proxy_pass http://localhost:5000/;
到这里:
location /
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
proxy_pass http://localhost:5000/;
This post 这里可以帮助提供有关 Nginx 反向代理中所需的 CORS 标头的更多信息
【讨论】:
【参考方案2】:尝试添加变量端口以访问环境变量。端口应设置为https://app.example.com/
const port = process.env.PORT || 3000
并在后端代码中使用本地主机 3000 的任何地方使用它。
这也应该有帮助
const io = require("socket.io")(server,
cors:
origin: port,
methods: ["GET", "POST"],
allowedHeaders: ['Access-Control-Allow-Origin'],
credentials: false
)
【讨论】:
以上是关于生产中的 Socket.io 返回 400 Bad Request 错误的主要内容,如果未能解决你的问题,请参考以下文章
HttpWebRequest-远程服务器返回错误:(400) Bad Request
Laravel 6 护照在错误的凭证上返回 400 Bad request