Javascript WebSocket连接失败:WebSocket握手期间出错:意外响应代码:400

Javascript WebSocket连接失败:WebSocket握手期间出错:意外响应代码:400,javascript,angularjs,node.js,sockets,socket.io,Javascript,Angularjs,Node.js,Sockets,Socket.io,我正在尝试将Socket.io与Angular集成,但在建立从客户端到服务器的连接时遇到了困难。我已经浏览过其他相关的问题,但是我的问题在本地发生,所以中间没有Web服务器。 这就是我的服务器代码的样子: const-app=express(); const server=http.createServer(app); const io=require('socket.io')。侦听(服务器); io.on('连接',函数(套接字){ emit('greet',{hello:'Hey,Mr.Cl

我正在尝试将Socket.io与Angular集成,但在建立从客户端到服务器的连接时遇到了困难。我已经浏览过其他相关的问题,但是我的问题在本地发生,所以中间没有Web服务器。 这就是我的服务器代码的样子:

const-app=express();
const server=http.createServer(app);
const io=require('socket.io')。侦听(服务器);
io.on('连接',函数(套接字){
emit('greet',{hello:'Hey,Mr.Client!'});
socket.on('response',函数(数据){
控制台日志(数据);
});
socket.on('disconnect',function()){
log(“套接字断开”);
});
});
我正在使用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,
        ...
    ]
}
然后在我的控制器中:

函数MyController($scope){
让socket=io.connect(window.location.href);
socket.connect('http://localhost:3000');
socket.on('greet',函数(数据){
控制台日志(数据);
emit('respond',{消息:'Hello to you too,Mr.Server!'});
});
...
}
在实际使用
btford/angular socket io
库之前,我想确保能够正确连接,但控制台中出现以下错误:

有趣的是,如果我重新启动Node.js服务器进程,它确实能够发送消息,但是使用轮询而不是WebSocket

我在socket.connect调用中尝试了各种不同的选项,但都没有成功

任何帮助都将不胜感激


更新(30/12/2016): 我刚刚意识到websockets在部分工作。我在Chrome开发者控制台中看到101交换协议请求。但是,我看到的唯一帧是engine.io协议包(ping、pong)。然而,由于某些原因,我的应用程序套接字消息仍然返回轮询


在控制器中,您使用的是
http
方案,但我认为您应该使用
ws
方案,就像您使用WebSocket一样。尝试在连接函数中使用
ws://localhost:3000

我认为您应该为客户端定义
源代码,如下所示:

//server.js
const socket=require('socket.io');
const-app=require('express')();
const server=app.listen('port');
const io=socket().attach(服务器);
io.origins(“您的\u域:端口www.your\u域:端口您的\u IP:port您的\u域:”)
io.on('连接',(套接字)=>{
log(“连接了一个新客户端”);
});
//client.js

var socket=io('ws://:port')问题已解决!我只是想知道如何解决这个问题,但我仍然想知道这是否是正常行为

看起来,即使Websocket连接建立正确(由101交换协议请求指示),它仍然默认为长轮询。修复非常简单,只需将此选项添加到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);
});
消息现在显示为帧:


这为我指明了正确的方向。感谢所有帮助过我的人

从您通过Socket.IO发送的消息判断
Socket.emit('greet',{hello:'Hey,Mr.Client!'}),似乎您正在使用
hackathonstarter
样板文件。如果是这样,问题可能是
express status monitor
模块正在创建自己的socket.io实例,如下所示:

您可以:

  • 移除该模块
  • 创建
    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、节点服务器和Angular 4很有效 将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";
    }
    

    我也遇到过同样的问题,我改进了apache2虚拟主机Entry并取得了成功

    注意:在服务器上,我成功地安装并使用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>
    
    
    ServerName pad.tejastank.com
    ServerAlias pad.tejastank.com
    服务器管理员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\u module/usr/lib/apache2/modules/mod\u headers.so
    LoadModule deflate_module/usr/lib/apache2/modules/module_deflate.so
    ProxyVia On
    代理请求关闭
    代理主机
    ProxyPasshttp://localhost:9001/ 重试=0超时=30
    ProxyPassReversehttp://localhost:9001/
    #这是通过代理处理websocket传输所必需的,因为
    #etherpad不使用特定的子文件夹,例如/ws/来处理此类流量。
    #取自https://github.com/ether/etherpad-lite/issues/2318#issuecomment-63548542
    #感谢博冈德森的语义学
    重新启动发动机
    RewriteCond%{QUERY_STRING}transport=websocket[NC]
    重写规则/(*)ws://localhost:9001/socket.io/$1[P,L]
    ProxyPasshttp://localhost:9001/socket.io 重试=0超时=30
    ProxyPassReversehttp://localhost:9001/socket.io
    选项如下符号链接多视图
    允许超越所有
    命令允许,拒绝
    通融
    
    提前提示: 请在a2enmod的帮助下启用apache2的所有mod


    重新启动apache2将生效。但显然需要一个启用站点的敏感度。

    您正在客户端使用端口3000。我猜是角端口而不是服务器端口?它应该连接到服务器端口。

    使用以下负载平衡器设置后,我的问题已为wss解决,但对于ws,特定ISP的问题仍然存在

    I s
       var socket = io.connect('xxx.xxx.xxx.xxx:8000', {
          transports: ['polling']
       });
    
    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
    
    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;
        }
    }
    
    <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>
    
    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;
    }
    
    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')
    }));
    
    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}`)
    })
    
    const app = require("express")();
    const http = require("http").Server(app);
    const io = require("socket.io")(http);
    
    http.listen(PORT,()=> console.log('listening'))
    
    app.listen(......)