I am trying to integrate Socket.io with Angular and I'm having difficulties making a connection from the client-side to the server. I've looked through other related questions but my issue is happening locally, so there's no web server in the middle.
This is what my server code looks like:
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'); }); }); I'm loading the client side JavaScript files using Grunt in the following order:
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, ... ] } Then in my controller:
function MyController($scope) { let socket = io.connect(window.location.href); socket.connect('); socket.on('greet', function(data) { console.log(data); socket.emit('respond', { message: 'Hello to you too, Mr.Server!' }); }); ... } Before actually using the btford/angular-socket-io library, I want to make sure that I can get a connection correctly, but I get the following error in the console:
The interesting thing is that if I restart the Node.js server process, it does manage to send the message but using polling instead of websockets.
I tried all sorts of different options in the socket.connect call, but nothing worked.
Any help would be appreciated.
UPDATE (30/12/2016):
I just realized that websockets is working partially. I see a 101 Switching Protocols request in the Chrome developer console. However the only frames I see there are the engine.io protocol packets (ping, pong). However my application socket messages still fall back to polling for some reason...
318 Answers
Problem solved! I just figured out how to solve the issue, but I would still like to know if this is normal behavior or not.
It seems that even though the Websocket connection establishes correctly (indicated by the 101 Switching Protocols request), it still defaults to long-polling. The fix was as simple as adding this option to the Socket.io connection function:
{transports: ['websocket']} So the code finally looks like this:
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'); }); }); and on the 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); }); And the messages now appear as frames:
This Github issue pointed me in the right direction. Thanks to everyone who helped out!
6This worked for me with Nginx, Node server and Angular 4
Edit your nginx web server config file as:
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 ""; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } 6The currently accepted solution is misleading.
According to the official documentation, adding the transports: [ 'websocket' ] option effectively removes the ability to fallback to long-polling when the websocket connection cannot be established. This option is what makes socket.io so robust in the first place because it can adapt to many scenarios.
In that particular case where one wishes to solely rely on websockets, directly using the WebSocket API is recommended.
For other cases (supposedly most users), this is most likely a reverse proxy/server configuration problem.
The official documentation suggests the following depending on your environment:
NginX configuration
http { server { listen 3000; server_name io.yourhost.com; location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_pass # enable WebSockets proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } upstream nodes { # enable sticky session based on IP ip_hash; server app01:3000; server app02:3000; server app03:3000; } } Apache HTTPD configuration
Header add Set-Cookie "SERVERID=sticky.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED <Proxy "balancer://nodes_polling"> BalancerMember "" route=app01 BalancerMember "" route=app02 BalancerMember "" route=app03 ProxySet stickysession=SERVERID </Proxy> <Proxy "balancer://nodes_ws"> BalancerMember "ws://app01:3000" route=app01 BalancerMember "ws://app02:3000" route=app02 BalancerMember "ws://app03:3000" route=app03 ProxySet stickysession=SERVERID </Proxy> RewriteEngine On RewriteCond %{HTTP:Upgrade} =websocket [NC] RewriteRule /(.*) balancer://nodes_ws/$1 [P,L] RewriteCond %{HTTP:Upgrade} !=websocket [NC] RewriteRule /(.*) balancer://nodes_polling/$1 [P,L] ProxyTimeout 3 HAProxy configuration
listen chat bind *:80 default_backend nodes backend nodes option httpchk HEAD /health http-check expect status 200 cookie io prefix indirect nocache # using the `io` cookie set upon handshake server app01 app01:3000 check cookie app01 server app02 app02:3000 check cookie app02 server app03 app03:3000 check cookie app03 Also worth reading this on upgrading connections in HAProxy.
For more details please refer to the official documentation link above.
EDIT:
Varnish (source here)
sub vcl_recv { if (req.http.upgrade ~ "(?i)websocket") { return (pipe); } } sub vcl_pipe { if (req.http.upgrade) { set bereq.http.upgrade = req.http.upgrade; set bereq.http.connection = req.http.connection; } } 3I solved this by changing transports from 'websocket' to 'polling'
var socket = io.connect('xxx.xxx.xxx.xxx:8000', { transports: ['polling'] }); 1Judging from the messages you send via Socket.IO socket.emit('greet', { hello: 'Hey, Mr.Client!' });, it seems that you are using the hackathon-starter boilerplate. If so, the issue might be that express-status-monitor module is creating its own socket.io instance, as per:
You can either:
- Remove that module
Pass in your socket.io instance and port as
websocketwhen you create theexpressStatusMonitorinstance like below:const server = require('http').Server(app); const io = require('socket.io')(server); ... app.use(expressStatusMonitor({ websocket: io, port: app.get('port') }));
Had the same issue, my app is behind nginx. Making these changes to my Nginx config removed the error.
location / { proxy_pass proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; } 0I had faced same issues, I refined apache2 virtual host entery and got success.
Note: on server I had succesful installed and working on 9001 port without any issue. This guide line for apache2 only no relavence with nginx, this answer for apache2+etherpad lovers.
<VirtualHost *:80> ServerName pad.tejastank.com ServerAlias pad.tejastank.com ServerAdmin 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 retry=0 timeout=30 ProxyPassReverse </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 # Thanks to beaugunderson for the semantics RewriteEngine On RewriteCond %{QUERY_STRING} transport=websocket [NC] RewriteRule /(.*) ws://localhost:9001/ [P,L] ProxyPass retry=0 timeout=30 ProxyPassReverse </Location> <Proxy *> Options FollowSymLinks MultiViews AllowOverride All Order allow,deny allow from all </Proxy> </VirtualHost> Advance tips: Please with help of a2enmod enable all mod of apache2
Restart apache2 than will get effect. But obvious a2ensite to enable site required.
4I think you should define your origins for client side as bellow:
//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 your_IP:port your_domain:*") io.on('connection', (socket) => { console.log('connected a new client'); }); //client.js var socket = io('ws://:port');2In my case, I have just install express-status-monitor to get rid of this error
here are the settings
install express-status-monitor npm i express-status-monitor --save const expressStatusMonitor = require('express-status-monitor'); app.use(expressStatusMonitor({ websocket: io, port: app.get('port') })); The problem for me was not got the port from process.env.PORT it is very important because Heroku and other services properly do a random port numbers to use.
So that is the code that work for me eventuly :
var app = require('express')(); var http = require('http').createServer(app); const serverPort = process.env.PORT ; //<----- important const io = require('socket.io')(http,{ cors: { origin: '*', methods: 'GET,PUT,POST,DELETE,OPTIONS'.split(','), credentials: true } }); http.listen(serverPort,()=>{ console.log(`server listening on port ${serverPort}`) }) I had the same error witk socket.io on node.js but the reason was quite silly. There wasn't all socket.io's dependencies installed correctly, namely package base64id was missed
In your controller, you are using an http scheme, but I think you should be using a ws scheme, as you are using websockets. Try to use ws://localhost:3000 in your connect function.
You're using port 3000 on the client-side. I'd hazard a guess that's the Angular port and not the server port? It should be connecting to the server port.
After using following load balancer setting my problem solved for wss but for ws problem still exists for specific one ISP.
I solved this by removing io.listen(server);. I started running into this error when I started integrating passport.socketio and using passport middleware.
if you are using httpd/apache, you can add a file something like ws.conf and add this code to it. Also, this solution can proxy something like this "" to just this ""
<VirtualHost *:80> RewriteEngine on #redirect WebSocket RewriteCond %{REQUEST_URI} ^/socket.io [NC] RewriteCond %{QUERY_STRING} transport=websocket [NC] RewriteRule /(.*) ws://localhost:6001/$1 [P,L] ProxyPass /socket.io ProxyPassReverse /socket.io </VirtualHost> Using Apollo Server 2.
try 'ws://localhost:4000/graphql'
...since incoming and outgoing requests now use the same address.
my problem was with server side
const app = require("express")(); const http = require("http").Server(app); const io = require("socket.io")(http); listen with
http.listen(PORT,()=> console.log('listening')) it was giving me error when i did
app.listen(......)



