web-dev-qa-db-ja.com

WebSocket接続に失敗しました:WebSocketハンドシェイク中のエラー:予期しない応答コード:400

Socket.ioをAngularと統合しようとしていますが、クライアント側からサーバーへの接続に問題があります。他の関連する質問に目を通しましたが、私の問題はローカルで発生しているため、途中にWebサーバーはありません。

これは私のサーバーコードのようです:

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ライブラリを実際に使用する前に、正しく接続できることを確認したいのですが、コンソールに次のエラーが表示されます。

socket io connection error message

興味深いのは、Node.jsサーバープロセスを再起動すると、websocketの代わりにポーリングを使用してメッセージを送信できることです。

after restart

polling message

Socket.connect呼び出しでさまざまなオプションを試しましたが、何も機能しませんでした。

任意の助けをいただければ幸いです。


更新(2016年12月30日):

Websocketが部分的に機能していることに気付きました。 Chrome開発者コンソールに101スイッチングプロトコルリクエストが表示されます。ただし、表示されるフレームはengine.ioプロトコルパケット(ping、pong)のみです。ただし、アプリケーションソケットメッセージは、何らかの理由でまだポーリングにフォールバックしています...

engine.io packets

30
ashe540

問題が解決しました!私は問題を解決する方法を考え出しましたが、これが通常の動作であるかどうかを知りたいです。

(101 Switching Protocolsリクエストで示される)Websocket接続が正しく確立されたとしても、デフォルトではロングポーリングが行われているようです。修正は、このオプションを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);
});

メッセージはフレームとして表示されます:

作業中のWebソケット

この Githubの問題 は正しい方向を示してくれました。手伝ってくれたみんなに感謝します!

38
ashe540

これは、Nginx、Nodeサーバー、および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";
}
12
Abhijeet

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-in-project

次のいずれかを実行できます。

  1. そのモジュールを削除する
  2. 次のようにwebsocketインスタンスを作成するときに、socket.ioインスタンスとポートをexpressStatusMonitorとして渡します。

    const server = require('http').Server(app);
    const io = require('socket.io')(server);
    ...
    app.use(expressStatusMonitor({ websocket: io, port: app.get('port') })); 
    
8
Kuriakin Zeng

トランスポートを「websocket」から「polling」に変更することでこれを解決しました

   var socket = io.connect('xxx.xxx.xxx.xxx:8000', {
      transports: ['polling']
   });
3

私は同じ問題に直面していましたが、Apache2バーチャルホストを改良して成功しました。

注:サーバーに問題なくインストールされ、9001ポートで正常に動作していました。 Apache2のこのガイドラインは、nginxとの関係はありません。Apache2+ etherpadの愛好家向けの回答です。

<VirtualHost *:80>
  ServerName pad.tejastank.com
  ServerAlias pad.tejastank.com
  ServerAdmin [email protected]

  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は明らかです。

1
Tejas Tank

io.listen(server);を削除することでこれを解決しました。 passport.socketioの統合とパスポートミドルウェアの使用を開始したときに、このエラーが発生し始めました。

0
David

次のようにクライアント側の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');
0
Saeid Alidadi

クライアント側でポート3000を使用しています。サーバーポートではなくAngularポートであると推測して危険です。サーバーポートに接続する必要があります。

0
martinedwards

コントローラーでは、httpスキームを使用していますが、websocketを使用しているので、wsスキームを使用する必要があります。接続関数でws://localhost:3000を使用してみてください。

0
TeaMonkie

次のロードバランサーの設定を使用した後、WSSの問題は解決しましたが、WSの問題は特定の1つのISPに引き続き存在します。

calssic-load-balancer

0
Mamun Hasan