![](/img/trans.png)
[英]Meteor WebSocket connection to 'ws://…/websocket' failed: Error during WebSocket handshake: Unexpected response code: 400
[英]WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400
我正在尝试将 Socket.io 与 Angular 集成,但在建立从客户端到服务器的连接时遇到了困难。 我查看了其他相关问题,但我的问题发生在本地,所以中间没有网络服务器。
这是我的服务器代码的样子:
const app = express();
const server = http.createServer(app);
const io = require('socket.io').listen(server);
io.on('connection', function(socket) {
socket.emit('greet', { hello: 'Hey, Mr.Client!' });
socket.on('respond', function(data) {
console.log(data);
});
socket.on('disconnect', function() {
console.log('Socket disconnected');
});
});
我按以下顺序使用 Grunt 加载客户端 JavaScript 文件:
dist: {
src: [
public/bower_components/angular/angular.min.js,
...
public/bower_components/socket.io-client/dist/socket.io.min.js,
public/bower_components/angular-socket-io/socket.min.js,
...
]
}
然后在我的控制器中:
function MyController($scope) {
let socket = io.connect(window.location.href);
socket.connect('http://localhost:3000');
socket.on('greet', function(data) {
console.log(data);
socket.emit('respond', { message: 'Hello to you too, Mr.Server!' });
});
...
}
在实际使用btford/angular-socket-io
库之前,我想确保我可以正确获得连接,但我在控制台中收到以下错误:
有趣的是,如果我重新启动 Node.js 服务器进程,它确实可以发送消息,但使用轮询而不是 websockets。
我在 socket.connect 调用中尝试了各种不同的选项,但没有任何效果。
任何帮助,将不胜感激。
我刚刚意识到 websockets 正在部分工作。 我在 Chrome 开发者控制台中看到 101 Switching Protocols 请求。 然而,我看到的唯一帧是 engine.io 协议数据包(ping、pong)。 但是,由于某种原因,我的应用程序套接字消息仍然退回到轮询...
问题解决了! 我只是想出了如何解决这个问题,但我仍然想知道这是否是正常行为。
似乎即使 Websocket 连接建立正确(由 101 Switching Protocols 请求指示),它仍然默认为长轮询。 修复就像将这个选项添加到 Socket.io 连接函数一样简单:
{transports: ['websocket']}
所以代码最终看起来像这样:
const app = express();
const server = http.createServer(app);
var io = require('socket.io')(server);
io.on('connection', function(socket) {
console.log('connected socket!');
socket.on('greet', function(data) {
console.log(data);
socket.emit('respond', { hello: 'Hey, Mr.Client!' });
});
socket.on('disconnect', function() {
console.log('Socket disconnected');
});
});
在客户端:
var socket = io('ws://localhost:3000', {transports: ['websocket']});
socket.on('connect', function () {
console.log('connected!');
socket.emit('greet', { message: 'Hello Mr.Server!' });
});
socket.on('respond', function (data) {
console.log(data);
});
消息现在显示为帧:
这个Github 问题为我指明了正确的方向。 感谢所有帮助过的人!
将您的 nginx Web 服务器配置文件编辑为:
server {
listen 80;
server_name 52.xx.xxx.xx;
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass "http://127.0.0.1:4200";
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
当前 接受的解决方案具有误导性。
根据官方文档,添加transports: [ 'websocket' ]
选项有效地消除了当 websocket 连接无法建立时回退到长轮询的能力。 这个选项首先使socket.io
如此强大,因为它可以适应许多场景。
在希望仅依赖 websocket 的特定情况下,建议直接使用WebSocket API
。
对于其他情况(假设是大多数用户),这很可能是反向代理/服务器配置问题。
官方文档根据您的环境提出以下建议:
http {
server {
listen 3000;
server_name io.yourhost.com;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://nodes;
# enable WebSockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
upstream nodes {
# enable sticky session based on IP
ip_hash;
server app01:3000;
server app02:3000;
server app03:3000;
}
}
Header add Set-Cookie "SERVERID=sticky.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<Proxy "balancer://nodes_polling">
BalancerMember "http://app01:3000" route=app01
BalancerMember "http://app02:3000" route=app02
BalancerMember "http://app03:3000" route=app03
ProxySet stickysession=SERVERID
</Proxy>
<Proxy "balancer://nodes_ws">
BalancerMember "ws://app01:3000" route=app01
BalancerMember "ws://app02:3000" route=app02
BalancerMember "ws://app03:3000" route=app03
ProxySet stickysession=SERVERID
</Proxy>
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) balancer://nodes_ws/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) balancer://nodes_polling/$1 [P,L]
ProxyTimeout 3
listen chat
bind *:80
default_backend nodes
backend nodes
option httpchk HEAD /health
http-check expect status 200
cookie io prefix indirect nocache # using the `io` cookie set upon handshake
server app01 app01:3000 check cookie app01
server app02 app02:3000 check cookie app02
server app03 app03:3000 check cookie app03
在 HAProxy 中升级连接也值得一读。
更多详细信息请参考上面的官方文档链接。
编辑:
sub vcl_recv {
if (req.http.upgrade ~ "(?i)websocket") {
return (pipe);
}
}
sub vcl_pipe {
if (req.http.upgrade) {
set bereq.http.upgrade = req.http.upgrade;
set bereq.http.connection = req.http.connection;
}
}
我通过将传输从“websocket”更改为“轮询”解决了这个问题
var socket = io.connect('xxx.xxx.xxx.xxx:8000', {
transports: ['polling']
});
从你通过 Socket.IO 发送的消息来看socket.emit('greet', { hello: 'Hey, Mr.Client!' });
,您似乎正在使用hackathon-starter
样板。 如果是这样,问题可能是express-status-monitor
模块正在创建自己的 socket.io 实例,根据: https ://github.com/RafalWilinski/express-status-monitor#using-module-with-socketio- 项目内
您可以:
当您创建expressStatusMonitor
实例时,将您的 socket.io 实例和端口作为websocket
传递,如下所示:
const server = require('http').Server(app); const io = require('socket.io')(server); ... app.use(expressStatusMonitor({ websocket: io, port: app.get('port') }));
有同样的问题,我的应用程序落后于 nginx。 对我的 Nginx 配置进行这些更改消除了错误。
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
我也遇到过同样的问题,我改进了 apache2 虚拟主机并获得了成功。
注意:在服务器上,我已成功安装并在 9001 端口上工作,没有任何问题。 apache2 的此指南仅与 nginx 无关,此答案适用于 apache2+etherpad 爱好者。
<VirtualHost *:80>
ServerName pad.tejastank.com
ServerAlias pad.tejastank.com
ServerAdmin snippetbucket@gmail.com
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
LoadModule deflate_module /usr/lib/apache2/modules/mod_deflate.so
ProxyVia On
ProxyRequests Off
ProxyPreserveHost on
<Location />
ProxyPass http://localhost:9001/ retry=0 timeout=30
ProxyPassReverse http://localhost:9001/
</Location>
<Location /socket.io>
# This is needed to handle the websocket transport through the proxy, since
# etherpad does not use a specific sub-folder, such as /ws/ to handle this kind of traffic.
# Taken from https://github.com/ether/etherpad-lite/issues/2318#issuecomment-63548542
# Thanks to beaugunderson for the semantics
RewriteEngine On
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule /(.*) ws://localhost:9001/socket.io/$1 [P,L]
ProxyPass http://localhost:9001/socket.io retry=0 timeout=30
ProxyPassReverse http://localhost:9001/socket.io
</Location>
<Proxy *>
Options FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
</Proxy>
</VirtualHost>
进阶提示:请在 a2enmod 的帮助下启用 apache2 的所有 mod
重启 apache2 即可生效。 但显然 a2ensite 需要启用站点。
我认为您应该将客户端的origins
定义如下:
//server.js const socket = require('socket.io'); const app = require('express')(); const server = app.listen('port'); const io = socket().attach(server); io.origins("your_domain:port www.your_domain:port your_IP:port your_domain:*") io.on('connection', (socket) => { console.log('connected a new client'); }); //client.js var socket = io('ws://:port');
就我而言,我刚刚安装了 express-status-monitor 以消除此错误
这是设置
install express-status-monitor
npm i express-status-monitor --save
const expressStatusMonitor = require('express-status-monitor');
app.use(expressStatusMonitor({
websocket: io,
port: app.get('port')
}));
对我来说,问题不是从process.env.PORT
获得端口,这非常重要,因为 Heroku 和其他服务正确地使用了随机端口号。
这就是最终对我有用的代码:
var app = require('express')();
var http = require('http').createServer(app);
const serverPort = process.env.PORT ; //<----- important
const io = require('socket.io')(http,{
cors: {
origin: '*',
methods: 'GET,PUT,POST,DELETE,OPTIONS'.split(','),
credentials: true
}
});
http.listen(serverPort,()=>{
console.log(`server listening on port ${serverPort}`)
})
我在 node.js 上遇到了同样的错误 witk socket.io,但原因很愚蠢。 没有正确安装socket.io的所有依赖,即缺少包base64id
在您的控制器中,您使用的是http
方案,但我认为您应该使用ws
方案,因为您正在使用 websockets。 尝试在您的连接函数中使用ws://localhost:3000
。
您在客户端使用端口 3000。 我会冒险猜测那是 Angular 端口而不是服务器端口? 它应该连接到服务器端口。
在使用以下负载平衡器设置后,我的问题解决了 wss 但对于特定的一个 ISP,ws 问题仍然存在。
我通过删除io.listen(server);
解决了这个问题。 . 当我开始集成passport.socketio 并使用passport 中间件时,我开始遇到这个错误。
如果您使用的是 httpd/apache,您可以添加类似 ws.conf 的文件并将此代码添加到其中。 此外,此解决方案可以将类似“http://localhost:6001/socket.io”的内容代理到“http://localhost/socket.io”
<VirtualHost *:80>
RewriteEngine on
#redirect WebSocket
RewriteCond %{REQUEST_URI} ^/socket.io [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule /(.*) ws://localhost:6001/$1 [P,L]
ProxyPass /socket.io http://localhost:6001/socket.io
ProxyPassReverse /socket.io http://localhost:6001/socket.io
</VirtualHost>
使用阿波罗服务器 2。
根据https://github.com/apollographql/apollo-client/issues/4778#issuecomment-509638071 ,这解决了我的问题:
试试 'ws://localhost:4000/graphql'
...因为传入和传出请求现在使用相同的地址。
我的问题出在服务器端
const app = require("express")();
const http = require("http").Server(app);
const io = require("socket.io")(http);
听
http.listen(PORT,()=> console.log('listening'))
当我这样做时它给了我错误
app.listen(......)
包括transports: ['websocket']
不是最好的方法,因为它删除了适合任何场景的 Sockt.io 功能。
在我使用 Nodejs + Nginx + Vuejs/Vite(Front) 的情况下,我设法通过在 Nginx 的站点配置中配置反向代理来解决它。
http {
server {
listen 80;
root /var/www/html;
// <---- start ---->
location /socket.io/ { // <--- Set your custom path
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://localhost:3000; // <--- Set your Port
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
// <---- End ---->
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.