socketio / socket.io

Realtime application framework (Node.JS server)
https://socket.io
MIT License
61.25k stars 10.12k forks source link

Error during WebSocket handshake: Unexpected response code: 400 #1942

Closed shi-yuan closed 7 years ago

shi-yuan commented 9 years ago

Can't find out a solution, I get this error on the browser console: WebSocket connection to 'ws://.../socket.io/?EIO=2&transport=websocket&sid=p3af7ZNfvogtq6tAAAG0' failed: Error during WebSocket handshake: Unexpected response code: 400.

Hava any advice ?

ZeldaZach commented 5 years ago

This config is in my sites-enabled/site.conf file, but it should work in htaccess too afaik

josephmiller2000 commented 5 years ago

All i can say, SSL is culprit here :) disable, cloudflare flexible SSL mode and move to FULL(STRICT) mode. Sure this will fix the issue, If not,

Use localhost:port in reverse proxy configuration.

gavinbelson commented 5 years ago

For anyone here using Nginx and React Express (MERN). I had the same issue because I only the the proxy_pass http://localhost:3000; line. I added the following lines based on @tylercb answer from above in this thread:

"Had the same issue, my app is behind nginx. Making these changes to my Nginx config removed the error.

location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}

This is originally from https://chrislea.com/2013/02/23/proxying-websockets-with-nginx/ "

andrzj commented 5 years ago

If anyone still having problems using Nodejs + Express, maybe your problem could be express-status-monitor, as @slaveofcode mentioned. As sated in its NPM documentation, this module spawn its own socket.io instance, so you should fill websocket parameter with your main socket.io instance, as well port parameter:

const io = require('socket.io')(server);
const expressStatusMonitor = require('express-status-monitor');
app.use(expressStatusMonitor({
  websocket: io,
  port: app.get('port')
}));
knifesk commented 5 years ago

This is my Apache config, notice it's using a /ws/ path prefix, but otherwise it works fine.

    ProxyRequests Off
    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

    RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^/ws/socket.io         [NC]
    RewriteCond %{QUERY_STRING} transport=websocket    [NC]
    RewriteRule /ws/(.*)           ws://localhost:6001/$1 [P,L]
    ProxyPass /ws http://127.0.0.1:6001
    ProxyPassReverse /ws http://127.0.0.1:6001
oceaneLonneux commented 5 years ago

Currently facing this issue with exposing the Linkerd dashboard (service mesh) for our EKS cluster. we use nginx, so not exactly sure how to get out of that one at this moment.

mb8z commented 5 years ago

@andrzj OMG man, you just saved me.

Kevinlinpr commented 5 years ago

Had the same issue, my app is behind nginx. Making these changes to my Nginx config removed the error.

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

This is originally from https://chrislea.com/2013/02/23/proxying-websockets-with-nginx/

it works.

nikodunk commented 5 years ago

Thanks for the help gang! If anyone is trying to get this working next to normal HTTPS traffic, it's now working on Elastic Beanstalk for me with the following settings:

santhosh77h commented 5 years ago

If you guys are still having this issue and you have set allowed origin in socket server as array or origins instead of callback function to filter origins would throw this error

Error during WebSocket handshake: Unexpected response code: 400

In my case updating this logic

io.origins(['https://foo.example.com:443']);

to this

io.origins((origin, callback) => {  
     if (origin !== 'https://foo.example.com') {    
         return callback('origin not allowed', false);  
     }  
    callback(null, true);
});

Worked without any errors thrown.

ecda909 commented 5 years ago

Getting this same error, but I added in the configs for NGINX and I am still receiving the same 400 handshake error. I am however, using an Application Load Balancer in AWS and I have it set to an :80 Target Group and a 443 listener which forwards to the Target Group.

NGINX conf file:

`server {

listen [::]:80;
listen 80;

server_name <domain_name>;
access_log  /var/log/nginx/access.log;

location / {
    proxy_pass http://127.0.0.1:8000;
    include proxy_params;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
}

location /socket.io {
    include proxy_params;
    proxy_http_version 1.1;
    proxy_cache_bypass $http_upgrade;
    proxy_buffering off;
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_pass http://127.0.0.1:8000;
}

}`

And within my js file I have a connection for socket.io that looks like this: var socket = io()

e1016 commented 4 years ago

Create manual instance (without express app instance) and assign a different port

const io = require('socket.io')(3001, {
  path: '/',
  serveClient: false,
  // below are engine.IO options
  pingInterval: 10000,
  pingTimeout: 5000,
  cookie: false
})
EduardsE commented 4 years ago

Had the same issue, my app is behind nginx. Making these changes to my Nginx config removed the error.

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

This is originally from https://chrislea.com/2013/02/23/proxying-websockets-with-nginx/

I was missing proxy_set_header Connection "upgrade";

yingshaoxo commented 4 years ago

I've been spending a whole night to solve this problem when I start to use https or wss or ssl. It always says connection stopped before establish with 400 error code.

Just a minutes ago, I found a solution for that:

0. Cloudflare

At the SSL/TLS tab:

If you are not sure what you are doing, just go to DNS tab, set DNS only

1. Make sure you have a right proxy configuration.

server {
    listen 80;
    server_name ai-tools-online.xyz;
    return 301 https://ai-tools-online.xyz$request_uri;
}

server {
    listen 443 ssl http2;

    ssl_certificate       /data/v2ray.crt;
    ssl_certificate_key   /data/v2ray.key;
    ssl_protocols         TLSv1.2 TLSv1.3;
    #ssl_ciphers           3DES:RSA+3DES:!MD5;
    server_name ai-tools-online.xyz;

    location / {
        proxy_pass http://127.0.0.1:5000;
    }

    location /socket.io {
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://127.0.0.1:5000/socket.io;
    }
}

ai-tools-online.xyz is your domain, http://127.0.0.1:5000 is your socket server.

2. Make sure your server Cross-Origin Controls is set to '*' to allow Cross-Origin Access

For flask-socketio, is to use flask_socketio.SocketIO(app, cors_allowed_origins = '*')

3. You must restart the nginx to let the new config work

systemctl restart nginx

4. For more details about how to set caddy, see the following links:

https://github.com/yingshaoxo/Web-Math-Chat#reverse-proxy-configuration-for-https https://caddy.community/t/using-caddy-0-9-1-with-socket-io-and-flask-socket-io/508/6 https://www.nginx.com/blog/nginx-nodejs-websockets-socketio/

debaosuidecl commented 4 years ago

I googled because I got the same problem and I also use nginx. The solution is to add this part

proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host;

into the nginx configuration file like tylercb mentioned.

worked for me well thank you !

flyingabhijeet commented 4 years ago

If you are using Elastic Beanstalk just like me to create node-server, While creating the environment we are being asked in configurations to use which Proxy Server. In which nginx is pre-populated or default set. I set that proxy server to none and then continued to continue creating my server. I was using Elastic Beanstalk to create a node server in which my proxy server was default set to nginx. As it is an error of configuring proxy server. After removing any proxy server, the error disappeared.

luigimannoni commented 4 years ago

Been googling for hours and none of the solutions above applied to us since we just had a nodejs app and no nginx.

The way we solved this was just to disable nginx from the container -> load balancer settings to pass all traffic directly to node.

cacothi commented 4 years ago

Been googling for hours and none of the solutions above applied to us since we just had a nodejs app and no nginx.

The way we solved this was just to disable nginx from the container -> load balancer settings to pass all traffic directly to node.

how did you do that?

luigimannoni commented 4 years ago

If you go to Configuration > Load balancer you can find a drop-down for the proxy server, you can use nginx, Apache or set it to "none" to pass through all connections to the node app.

This only appears if you create an environment with a load balancer, doesn't work for single instances

Edit: my original comment was referred to Elastic Beanstalk

NazimMertBilgi commented 4 years ago

Had the same issue, my app is behind nginx. Making these changes to my Nginx config removed the error.

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

This is originally from https://chrislea.com/2013/02/23/proxying-websockets-with-nginx/

So so thank youuu.

theavuthnhel commented 4 years ago

This document is for those who use laravel-echo-server & Nginx & socket.io & Redis-server with the separated server between client project and Redis-server.

Please follow the link here.

Thanks

vankeer commented 4 years ago

I had this issue. Updating my nginx config didn't help, but @santhosh77h 's solution fixed it for me. For some reason passing the array of allowed origins doesn't work, but using the callback does.

I use Nest.js websockets (just a wrapper around Socket.io) and added the following to my gateway:

afterInit(server: Server): any {
    const origins = getOrigins(); // returns an array of origin strings
    server.origins((origin, cb) => {
      if (origins.includes(origin)) {
        cb(null, true)
      } else {
        cb('Invalid origin', false);
      }
    });
  }
jakubsuplicki commented 4 years ago

I had the same issue with NUXT.js with Node.js / Express running on AWS Elastic Beanstalk (Nginx proxy). Took me a few days to figure this out. I'll share my reading points. Maybe someone will find it useful.

My environment is on Application Load Balancer with two ports 80 for https and 443 for https with SSL.

In the combination of the answer from above, big thanks to @tylercb and official documentation from AWS and socket.io documentation I created an Nginx config file that seems to be fixing the issue.

I will quickly outline the steps:

In my index.js Node file:

const express = require('express')
const app = express()
const server = http.createServer(app)
const io = require('socket.io')(server)
const host = process.env.HOST || '127.0.0.1'
const port = process.env.PORT || 8081

On the front-end (one of my components): import io from 'socket.io-client'; in my Vue data(): socket: io()

Finally, In the application root, I created a folder .ebextensions Right inside I created a file 01-proxy.config with the following content:

files:
  /etc/nginx/conf.d/01-proxy.conf:
     mode: "000644"
     owner: root
     group: root
     content: |
        upstream nodejs {
          server 127.0.0.1:8081;
          keepalive 256;
        }
        server {
          listen 8080;
          server_name yourdomain.com;

          if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") {
            set $year $1;
            set $month $2;
            set $day $3;
            set $hour $4;
          }
          access_log /var/log/nginx/healthd/application.log.$year-$month-$day-$hour healthd;
          access_log  /var/log/nginx/access.log  main;

          location / {
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header Host $host;

              proxy_pass http://nodejs;

              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "upgrade";
          }

          gzip on;
          gzip_comp_level 4;
          gzip_types text/html text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

          location /static {
              alias /var/app/current/static;
          }

        }

  /opt/elasticbeanstalk/hooks/configdeploy/post/99_kill_default_nginx.sh:
    mode: "000755"
    owner: root
    group: root
    content: |
      #!/bin/bash -xe
      rm -f /etc/nginx/conf.d/00_elastic_beanstalk_proxy.conf
      service nginx stop 
      service nginx start

container_commands:
  removeconfig:
    command: "rm -f /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf /etc/nginx/conf.d/00_elastic_beanstalk_proxy.conf"

Additional readings: nginx configuration

That's it. Quite lengthy. My apologies and good luck.

knarasimhar commented 4 years ago

working for me below change in ubuntu and ngnix server for angular .net core

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

nighttiger1990 commented 4 years ago

If anyone still having problems using Nodejs + Express, maybe your problem could be express-status-monitor, as @slaveofcode mentioned. As sated in its NPM documentation, this module spawn its own socket.io instance, so you should fill websocket parameter with your main socket.io instance, as well port parameter:

const io = require('socket.io')(server);
const expressStatusMonitor = require('express-status-monitor');
app.use(expressStatusMonitor({
  websocket: io,
  port: app.get('port')
}));

This info helped me

LeonardoRick commented 4 years ago

Make sure you're socket.io connection isn't going through an Amazon Load Balancer. Or if so, do this: http://blog.flux7.com/web-apps-websockets-with-aws-elastic-load-balancing

If someone else had this issue using AWS load balancer, The article metioned doesn't say that it's possible too to use SSL as load balancer protocol and keep using your certificate on this configuration, out of you app server level.

This is how my LB listeners looks like

image

Worked well for me!

makaderbd commented 4 years ago

Had the same issue, my app is behind nginx. Making these changes to my Nginx config removed the error.

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

This is originally from https://chrislea.com/2013/02/23/proxying-websockets-with-nginx/

Yes. This was help-ful and worked for me as well.

andressspinetti commented 4 years ago

Make sure you're socket.io connection isn't going through an Amazon Load Balancer. Or if so, do this: http://blog.flux7.com/web-apps-websockets-with-aws-elastic-load-balancing

If someone else had this issue using AWS load balancer, The article metioned doesn't say that it's possible too to use SSL as load balancer protocol and keep using your certificate on this configuration, out of you app server level.

This is how my LB listeners looks like

image

Worked well for me!

Nice, it worked.

victorsferreira commented 4 years ago

Make sure you're socket.io connection isn't going through an Amazon Load Balancer. Or if so, do this: http://blog.flux7.com/web-apps-websockets-with-aws-elastic-load-balancing

If someone else had this issue using AWS load balancer, The article metioned doesn't say that it's possible too to use SSL as load balancer protocol and keep using your certificate on this configuration, out of you app server level.

This is how my LB listeners looks like

image

Worked well for me!

in this case your application is running on 80?

mjsaijem09 commented 3 years ago

Here

Page not found

helloalvin commented 3 years ago

我同样遇到了这个问题,我是wx小程序端+flask socketio, 后面设置SocketIO 的cors_allowed_origins='*' 解决了 400问题。

codeyourwayup commented 3 years ago

location /{ // your regular http config is here }

location /socket.io { proxy_http_version 1.1; proxy_buffering off; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_pass http://127.0.0.1:5000/socket.io; }


Above works form me!!

dev-improving commented 3 years ago

Had the same issue, my app is behind nginx. Making these changes to my Nginx config removed the error.

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

This is originally from https://chrislea.com/2013/02/23/proxying-websockets-with-nginx/

It works!!!! Now the thing is... how you figured out? XD

darrachequesne commented 3 years ago

For future readers, this issue is most certainly due to either:

Please check the documentation here: https://socket.io/docs/v4/reverse-proxy/

Please check the documentation here: https://socket.io/docs/v4/using-multiple-nodes/

And finally: https://socket.io/docs/v4/troubleshooting-connection-issues/