web-dev-qa-db-fra.com

Échec de la connexion WebSocket: erreur lors de l'établissement de la liaison WebSocket: Code de réponse inattendu: 400

J'essaie d'intégrer Socket.io à Angular et j'ai des difficultés à établir une connexion entre le client et le serveur. J'ai parcouru d'autres questions connexes, mais comme mon problème se pose localement, il n'y a pas de serveur Web au milieu.

Voici à quoi ressemble mon code serveur:

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');
  });
});

Je charge les fichiers JavaScript côté client à l'aide de Grunt dans l'ordre suivant:

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,
        ...
    ]
}

Puis dans mon contrôleur:

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!' });
    });

    ...
}

Avant d'utiliser réellement la bibliothèque btford/angular-socket-io, je veux m'assurer que je peux obtenir une connexion correctement, mais le message d'erreur suivant s'affiche dans la console:

 socket io connection error message

La chose intéressante est que si je redémarre le processus du serveur Node.js, il parvient à envoyer le message mais en utilisant la scrutation au lieu de websockets.

 after restart

 polling message

J'ai essayé toutes sortes d'options différentes dans l'appel socket.connect, mais rien n'a fonctionné.

Toute aide serait appréciée.


MISE À JOUR (30/12/2016):

Je viens de me rendre compte que websockets fonctionne partiellement. Je vois une demande 101 Switching Protocols dans la console de développement Chrome. Cependant, les seules images que je vois sont les paquets de protocole engine.io (ping, pong). Cependant, mes messages de socket d’application retiennent toujours la scrutation pour une raison quelconque ...

 engine.io packets

14
ashe540

Problème résolu! Je viens de comprendre comment résoudre le problème, mais j'aimerais quand même savoir s'il s'agit d'un comportement normal ou non.

Il semble que même si la connexion Websocket s'établit correctement (indiquée par la demande 101 Switching Protocols), elle reste par défaut à longue interrogation. Le correctif était aussi simple que d'ajouter cette option à la fonction de connexion Socket.io:

{transports: ['websocket']}

Donc, le code ressemble finalement à ceci:

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');
  });
});

et sur le client:

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);
});

Et les messages apparaissent maintenant sous forme de cadres:

Websockets de travail

Cette question Github m'a dirigé dans la bonne direction. Merci à tous ceux qui ont aidé! 

29
ashe540

Cela a fonctionné pour moi avec Nginx, Node Server et Angular 4

Editez le fichier de configuration de votre serveur Web nginx comme suit:

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";
}
8
Ab.Progr

À en juger par les messages que vous avez envoyés via Socket.IO socket.emit('greet', { hello: 'Hey, Mr.Client!' });, il semble que vous utilisiez le hackathon-starter warmplate. Si tel est le cas, il se peut que le module express-status-monitor crée sa propre instance socket.io, comme indiqué dans: https://github.com/RafalWilinski/express-status-monitor#using-module-with-socketio-in- projet

Tu peux soit:

  1. Supprimer ce module
  2. Transmettez votre instance socket.io et votre port sous la forme websocket lorsque vous créez l'instance expressStatusMonitor comme ci-dessous:

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

J'avais affronté les mêmes problèmes, j'ai affiné l'entité de l'hôte virtuel Apache2 et j'ai eu du succès.

Remarque: sur le serveur, je suis installé avec succès et je travaille sur le port 9001 sans aucun problème. Cette ligne de guide pour Apache2 ne contient aucune relation avec nginx, cette réponse pour les amateurs d’Apache2 +.

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

Conseils avancés: S'il vous plaît, avec l'aide de a2enmod, activez tous les mods d'Apache2

Redémarrez Apache2 pour obtenir un effet. Mais évident a2ensite pour activer le site requis.

1
Tejas Tank

Je pense que vous devriez définir votre origins pour le côté client comme suit:

//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

Dans votre contrôleur, vous utilisez un schéma http, mais je pense que vous devriez utiliser un schéma ws, car vous utilisez des websockets. Essayez d'utiliser ws://localhost:3000 dans votre fonction de connexion.

0
TeaMonkie