简体   繁体   中英

ExpressJS - Socket.IO with Route Separation

I'm trying to get my head around ExpressJS and Socket.IO. I've got my routes in a separate file which I include from my app.js:

var express = require('express')    
  , db = require('./db')
  , mongoose = require('mongoose')
  , models = require('./models/device')
  , http = require('http')
  , path = require('path')
  , app = express()
  , server = http.createServer(app)
  , io = require('socket.io').listen(server)
  , routes = require('./routes/myRoutes');

However when I try and emit an event from one of my routes I have no reference to socket.io.

exports.update = function(req, res){
    return Item.findById(req.params.id, function(err, item) {
       // Do some checks and save.
       socket.emit('updated');
    }
}

I understand why this might not be available. Rather I don't understand what the best way to get a handle on socket.io is from another file other than app.js. I was looking at this question (see Ricardo's answer) but I'm still not clear. Ideally I would like to avoid doing this:

routes = requires("routes/myRoutes")(io);

Well you don't really need express.io for that. The easiest solution would be to export a new module and pass it a reference to socket.io instance. So in your app.js you have :

var express = require('express'),
  ...
  , server = http.createServer(app)
  , io = require('socket.io').listen(server)
  , routes = require('./routes/myRoutes');

Now require a new module and pass it the socketio reference. Add this new line (in app.js) to do so :

require('./app/path/to/your/socketio/controller/socketio')(io);

Then create a new file in your path/to/your/socketio/controller called socketio.js

And finally in the socketio.js file, export your new module :

module.exports = function(io) {

    io.sockets.on('connection', function (socket) {

        socket.on('captain', function(data) {

            console.log(data);

            socket.emit('america');
        });
    });
};

And there you go!

Check out express.io

It has routing for realtime requests, and a bunch of other useful features.

app = require('express.io')()
app.http().io()

app.io.route('example', function(req) {
    // do something interesting
}))

app.listen(7076)

As far as getting around having to pass the io object around. You have a few options, which may or may not be "best" depending on who you ask.

  • Make io or app global. (some people freak out over globals)
  • Use module.exports and require the object in the other file. (can lead to circular dependency issues if not done properly)

Passing the io object is probably the cleanest simplest way, but you do have options.

socket.io doesn't work with routes, it works with sockets.

You add this code to app.js or a separate file which you include in app.js:

io.sockets.on('connection', function (socket) {
  socket.on('update', function (your_id) {
    Item.findById(your_id, function(err, item) {
      socket.emit('send_update', item);
    }
  });
});

Your update route only renders a html document with javascript, containing:

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.emit('update', { your_id: '1' });
  socket.on('send_update', function (data) {
    console.log(data);
  });
</script>

So once the page is rendered and complete, the client-javascript will open a socket to the server and receive additional data.

See more examples here.

Disclaimer: Code written from scratch and not tested.

The best way is to use closure. Ex:

exports.update = function(socket){
  return function(req, res) {
    //In here now you can have the reference to the socket io
    Item.findById(req.params.id, function(err, item) {
       // Do some checks and save.
       socket.emit('updated');
    }
  }
}

And:

app.post('/your_path', update(io));

I've used the middleware router of Expressjs (I'm using 4.x).

In the external route file I put the "next" object:

module.exports = function(app, settings){
    app.post('/something', function(req, res, next) {
    ...
    next();
    }
};

And in the main file I write the last route hop inside the io.on('connection'):

io.on('connection', function (socket) {

    // Final route for middlewares who need to interact with socket.io
    app.post('/something', function (req, res, next) {
        socket.emit('event', { result: 'ok' });
    });

});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM