I am trying to write a little app using Node.js, Express.js and Socket.IO.
The server runs fine and I can serve HTML and other static content. But I'm having a hell of a time getting the clients to connect via Socket.IO to the server.
When I don't use Express it works fine, but with Express I can't seem to get everything to cooperate. I am not sure if there are some special considerations when using Express and Socket.IO in conjunction.
Part of me thinks this could be a route issue?
It looks like when the socket tries to connect it is 404'ing:
GET http://localhost:3000/socket.io/1/?t=1403186531515 400 Bad Request 1ms
Server code:
var express = require('express')
, app = express()
, http = require('http')
, server = http.createServer(app).listen(3000)
, io = require('socket.io').listen(server)
, favicon = require('static-favicon')
, logger = require('morgan')
, cookieParser = require('cookie-parser')
, session = require('express-session')
, routes = require('./routes/index')
, path = require('path')
, bodyParser = require('body-parser');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hjs');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(session({secret: 'keyboard cat'}));
app.use(require('less-middleware')(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
io.sockets.on('connection', function (socket) {
//message new connection
socket.emit('message', { message: 'Message from server.' });
//message all connections
socket.on('send', function (data) {
io.sockets.emit('message', data);
});
});
Client code:
** html and other js omitted **
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/0.9.16/socket.io.min.js"></script>
<script>
var socket = io.connect('http://localhost:3000');
</script>
I have also tried
var socket = io.connect('ws://localhost:3000');
To no avail.
Thanks for any help!
Not sure why you use CDN on client, but you can use the local resource (served in backstage by socket.io)
So replace your script tags with:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect(); // or just io();
</script>
You can get more help in Socket.io Get Started simple chat example
Try swapping the order of when you bind the server to a port:
var express = require('express')
, app = express()
, http = require('http')
, server = http.Server(app)
, io = require('socket.io').listen(server)
server.listen(3000);
Shoutout to Doug Wilson for his comment on GitHub which helped me solve this issue.
just try :
var socket = io.connect();
Related
My web app (built on Node.js and Express) works fine locally, but when I deploy it to Heroku, I'm unable to connect to my Mongo Labs database. I've changed the connection string in my 'app.js' file to properly reflect the URI of the new Heroku Mongo Labs database (fake username and password substituted below). I've also tried several stackoverlow solutions can't connect to mongolab with node.js on heroku as well as https://devcenter.heroku.com/articles/getting-started-with-nodejs#using-mongodb but those don't seem to work either. I suspect this is slightly different because I'm using Mongoskin.
The original connection:
var db = mongo.db("mongodb://localhost:27017/userdir", {native_parser:true});
changed to the new connection:
var db = mongo.db("mongodb://user:pass#dbh23.mongolab.com:27237/heroku_app24581691",{native_parser:true});
Any ideas as to what I'm missing here?
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
// Database
var mongo = require('mongoskin');
var db = mongo.db("mongodb://user:pass#dbh23.mongolab.com:27237/heroku_app24581691", {native_parser:true});
// Make db accessible to the router
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// Make db accessible to the router
app.use(function(req,res,next){
req.db = db;
next();
});
app.use('/', routes);
app.use('/users', users);
/// catch 404 and forwarding to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
I answered this in the comments on my tutorial, but I'll answer it here too: I think it's likely that you need to use the environment variable referenced in the Heroku ducomentation you linked: process.env.MONGOLAB_URI ... my guess is that Heroku doesn't want you putting your username/password directly into the code (and with good reason, since that's not particularly secure). Give it a shot with:
var db = mongo.db(process.env.MONGOLAB_URI, {native_parser:true});
and see how that works out.
My application works when i specify a port number to socket.io that is diffrent from the server port number. The working code goes as follows:
This is my app.js file:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var configDB = require('./config/database.js');
var session = require('express-session');
var passport = require('passport');
var routes = require('./routes/index');
var auth = require('./routes/auth.js');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.set(process.env.PORT || 1337);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(require('stylus').middleware(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({ secret: 'mysessionsecret' }));
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect(configDB.url);
app.use('/', routes);
app.use('/auth', auth);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
var talk = require('./socket/talk.js')(app);
module.exports = app;
This is my talk.js file:
var init = function (app){
var server = require("http").createServer(app).listen(3000);
var io = require("socket.io").listen(server);
var socketioJwt = require("socketio-jwt");
var jwtSecret = require('../config/jwtSecret');
console.log("init");
io.set("authorization", socketioJwt.authorize({
secret: jwtSecret,
handshake: true
}));
io.sockets.on("connection", function (socket) {
console.log("connected");
socket.on("send", function (data) {
console.log(data);
var username = data.username;
var message = data.message;
var datetime = data.datetime;
socket.broadcast.emit("send", data);
});
socket.on("busy", function () {
socket.emit("busy");
socket.broadcast.emit("busy");
});
socket.on("free", function () {
socket.emit("free");
socket.broadcast.emit("free");
});
});
}
module.exports = init;
This is my script tag in index.ejs:
<script src="http://localhost:3000/socket.io/socket.io.js"></script>
And finally this is my io connect from the client:
socket = io("http://localhost:3000/",{
query: 'token=' + tok
});
This works but the problem is that i want to publish my site to Azure but it is not possible to let a Azure website listen to diffrent ports. At least i think it is not possible.
One of the many things I tried is changing the talk.js file to this:
var init = function (app){
var server = require("http").createServer(app).listen(app.get('port'));
var io = require("socket.io").listen(server);
...
But i it doesn't work. I always get something along the lines of http://localhost/socket.io/socket.io.js not found
If i change the script tag in my index.ejs file to this
<script src="http://cdn.socket.io/socket.io-1.2.1.js"></script>
The socket.io.js file gets loaded but when i connect form te client side i get a continious 404 not found error.
I looked at a lot of solutions online but none of them work. I really don't know what i am doing wrong.
This error comes from the bin/www.js file being called before app.js when using npm start. A quick solution is to bypass www.js, which is only used to handle some common errors, as it is suggested in this answer.
This github repo is an implementation of this solution and can be used as a starting point for any Express.js + socket.io application.
I am trying to create an Express app with Socket.IO. It seems like Express has changed quite a lot and most of the code online about getting the 2 to work together is out of date. This is what I have:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io').listen(http);
io.on('connection', function(socket){
console.log('a user connected');
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
The server starts ok and says
info - socket.io started
However the front-end has a 404 error on http://example.com:3000/socket.io/socket.io.js
edit
If I add
http.listen(8080);
The server runs twice on port 3000 and 8080, the 3000 version does not load socket.io.js and the 8080 version does. How can I have it so the server is only running on 3000? changing it to 3000 errors and it tries to listen twice
The answer was to make the changes in bin/www.js instead of app.js
#!/usr/bin/env node
var debug = require('debug')('test1');
var app = require('../app');
app.set('port', process.env.PORT || 3000);
var http = require('http').Server(app);
var io = require('socket.io')(http);
var server = http.listen(app.get('port'), function() {
debug('Express server listening on port ' + server.address().port);
});
Change the io include to:
var io = require('socket.io')(http);
And towards the bottom add something like:
http.listen(3000, function() {
console.log('Listening on port %d', http.address().port);
});
I am having problem with setting socketIO 1.1 up to work on Heroku. I'm running Express v4.2. The socketio runs perfectly on localhost. However, on Heroku, it gives this error:
From Heroku log:
2014-09-15T09:40:14.578660+00:00 app[web.1]: GET /socket.io/?EIO=3&transport=polling&t=1410774014583-86 404 6ms - 744b
From browser:
GET http://[mydomainname]/socket.io/?EIO=3&transport=polling&t=1410774080589-97 404 (Not Found) socket.io.js:2680Request.create socket.io.js:2680Request socket.io.js:2614XHR.request socket.io.js:2555XHR.doPoll socket.io.js:2585Polling.poll socket.io.js:2951Polling.doOpen socket.io.js:2895Transport.open socket.io.js:2106Socket.open socket.io.js:1580Socket socket.io.js:1467Socket socket.io.js:1419Manager.open.Manager.connect socket.io.js:272(anonymous function)
I have followed the recommended configurations in Socket IO documentations. Relevant code as follows:
var express = require('express');
/* routes */
var routes = require('./routes/index');
var users = require('./routes/users');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var cons = require('consolidate');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.engine('dust', cons.dust);
app.set('view engine', 'dust');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser('hashionhashion'));
app.use(require('less-middleware')(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
//routing
app.use('/', routes);
app.use('/users', users);
/// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
//start the server
var server = require('http').Server(app);
var io = require('socket.io').listen(server);
var ioSockets = {};
io.on('connection', function(socket) {
ioSockets[socket.id] = socket;
socket.emit('welcome', {message: socket.id});
socket.on('disconnect', function(socket) {
delete ioSockets[socket.id];
});
});
exports.ioSockets = ioSockets;
module.exports = app;
server.listen(3000, function() {
console.log('Congrats, nothing broke!! Listening on port %d', server.address().port);
});
In my client file, the script are as follows:
<script src="my_path_to/socket.io.js"></script>
<script>
var socket = io.connect();
var socketId = '';
socket.on('welcome', function (data) {
socketId = data.message;
});
</script>
I also tried io.connect to "http://localhost", "http://localhost:3000", and my Heroku app domain. All of them produces the same error.
Any help will be greatly appreciated!
The issue ends up to be a express one, which has since been corrected in versions after 4.10.0.
For your own reading:
https://github.com/strongloop/express/issues/2406
https://github.com/jshttp/on-finished/issues/10
Look like you change socket.io path. Because I saw src="my_path_to/socket.io.js". socket.io try to connect but got 404.
Is there a route of express handled '/socket.io/'?
Even you resolve the 404 error. You will hit the other error. Because currently on heroku you must set socket.io connect to a https address. Otherwise socket.io will work under polling.
More detail:
https://github.com/Automattic/engine.io/issues/261
I have created a new Express application. It generated app.js for me and I have then created the following index.js bringing in socket.io:
var app = require('./app');
server=app.listen(3000);
var io = require('socket.io');
var socket = io.listen(server, { log: false });
socket.on('connection', function (client){
console.log('socket connected!');
});
Can anyone advise how I would access socket.io within the routes files?
For reference, the default generated app.js is below:
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
/// catch 404 and forwarding to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
SocketIO does not work with routes it works with sockets.
That said you might want to use express-io instead as this specially made for this or if you are building a realtime web app then try using sailsjs which already has socketIO integrated to it.
Do this to your main app.js
app = require('express.io')()
app.http().io()
app.listen(7076)
Then on your routes do something like:
app.get('/', function(req, res) {
// Do normal req and res here
// Forward to realtime route
req.io.route('hello')
})
// This realtime route will handle the realtime request
app.io.route('hello', function(req) {
req.io.broadcast('hello visitor');
})
See the express-io documentation here.
Or you can do this if you really want to stick with express + socketio
On your app.js
server = http.createServer(app)
io = require('socket.io').listen(server)
require('.sockets')(io);
Then create a file sockets.js
module.exports = function(io) {
io.sockets.on('connection', function (socket) {
socket.on('captain', function(data) {
console.log(data);
socket.emit('Hello');
});
});
};
You can then call that to your routes/controllers.
The route:
const Router = require('express').Router
const router = new Router();
router.get('/my-route', (req, res, next) => {
console.log(req.app.locals.io) //io object
const io = req.app.locals.io
io.emit('my event', { my: 'data' }) //emit to everyone
res.send("OK")
});
module.exports = router
The main file:
const app = require('express')()
const server = require('http').Server(app);
const io = require('socket.io')(server)
const myroute = require("./route") //route file dir
app.use(myroute);
server.listen(3000, () => {
console.log('¡Usando el puerto 3000!');
});
app.locals.io = io
I think a better way to do it is to attach the Io server to response object In the first middleware .per the way express is designed the Io server will be available to your subsequent routes.
Check this link