Ошибка подключения WebSocket: ошибка при рукопожатии WebSocket: непредвиденный код ответа: 400

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

socket io connection error message

интересно то, что если я перезапущу узел.процесс сервера js, ему удается отправить сообщение, но используя опрос вместо websockets.

after restart

polling message

Я пробовал все виды различных опций в сокете.connect call, но ничего не сработало.

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


обновление (30/12/2016):

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

engine.io packets

6 ответов


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

кажется, что, хотя соединение Websocket устанавливается правильно (указано запросом 101 протокола переключения), оно по-прежнему по умолчанию имеет длинный опрос. Исправление было так же просто, как добавление этой опции в сокет.функция подключения 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);
});

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

рабочие websockets

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


судя по сообщениям, которые вы отправляете через сокет.IO socket.emit('greet', { hello: 'Hey, Mr.Client!' }); похоже, что вы используете hackathon-starter boilerplate. Если это так, проблема может быть в том, что express-status-monitor модуль создает свой собственный сокет.экземпляр io, согласно: https://github.com/RafalWilinski/express-status-monitor#using-module-with-socketio-in-project

вы можете:

  1. удалить модуль
  2. Pass в вашем гнезде.экземпляр io и порт as websocket когда вы создайте expressStatusMonitor экземпляра, как показано ниже:

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

это сработало для меня с Nginx, Node server и 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";
}

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


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

я столкнулся с теми же проблемами, я усовершенствовал виртуальный хост apache2 и получил успех.

Примечание: На сервере я успешно установил и работал над портом 9001 без каких-либо проблем. Эта направляющая линия для apache2 только без relavence с 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/ [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

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