Не удалось подключиться к WebSocket: ошибка при рукопожатии WebSocket: неожиданный код ответа: 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');
  });
});

Я загружаю файлы JavaScript на стороне клиента с помощью Grunt в следующем порядке:

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, я хочу убедиться, что я могу правильно установить соединение, но я получаю следующую ошибку в консоли:

сообщение об ошибке соединения сокета io

Интересно, что если я перезапущу серверный процесс Node.js, ему удастся отправить сообщение, но с помощью опроса вместо веб-сайтов.

после перезапуска

сообщение для опроса

Я пробовал всевозможные опции в вызове socket.connect, но ничего не работало.

Любая помощь будет оценена.


ОБНОВЛЕНИЕ (30/12/2016):

Я только понял, что websockets работает частично. Я вижу запрос 101 Switching Protocols в консоли разработчика Chrome. Однако единственными кадрами, которые я вижу там, являются пакеты протокола engine.io(пинг, понг). Однако мои сообщения сокета приложения все еще возвращаются к опросу по какой-то причине...

engine.io-пакеты

Ответ 1

Проблема решена! Я просто понял, как решить проблему, но мне все равно хотелось бы знать, нормальное поведение или нет.

Похоже, что даже если соединение 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);
});

И сообщения теперь отображаются как кадры:

рабочие веб-сайты

Этот вопрос Github указал мне в правильном направлении. Спасибо всем, кто помог!

Ответ 2

Это работало для меня с сервером Nginx, Node и Angular 4

Измените конфигурационный файл веб-сервера nginx как:

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

Ответ 3

Судя по сообщениям, которые вы отправляете через 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- в-проект

Вы также можете:

  1. Удалить этот модуль
  2. Передайте ваш экземпляр socket.io и порт как websocket при создании экземпляра expressStatusMonitor как expressStatusMonitor ниже:

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

Ответ 4

Я решил это, изменив транспорты с "websocket" на "опрос"

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

Ответ 5

Я столкнулся с такими же проблемами, я усовершенствовал процесс виртуального хоста 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 включить весь mod of apache2

Перезапустите apache2, чем получите эффект. Но очевидный a2ensite для обеспечения требуемого сайта.

Ответ 6

В вашем контроллере вы используете схему http, но я думаю, что вы должны использовать схему ws, поскольку вы используете websockets. Попытайтесь использовать ws://localhost:3000 в своей функции подключения.

Ответ 7

Я думаю, что вы должны определить свою 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');

Ответ 8

Вы используете порт 3000 на стороне клиента. Я бы рискнул предположить, что угловой порт, а не порт сервера? Это должно быть подключение к порту сервера.

Ответ 9

После использования следующей настройки балансировки нагрузки моя проблема решена для wss, но для ws проблема все еще существует для конкретного провайдера.

calssic-балансировки нагрузки

Ответ 10

Я решил это, удалив io.listen(server);. Я начал сталкиваться с этой ошибкой, когда начал интегрировать passport.socketio и использовать промежуточное ПО для паспортов.