简体   繁体   English

ExpressJS - 具有路由分离的Socket.IO

[英]ExpressJS - Socket.IO with Route Separation

I'm trying to get my head around ExpressJS and Socket.IO. 我试图了解ExpressJS和Socket.IO。 I've got my routes in a separate file which I include from my app.js: 我的路由在一个单独的文件中,我从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. 但是,当我尝试从我的一个路由发出一个事件时,我没有引用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. 相反,我不明白获取socket.io句柄的最佳方法是从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); routes = requires(“routes / myRoutes”)(io);

Well you don't really need express.io for that. 那么你真的不需要express.io。 The easiest solution would be to export a new module and pass it a reference to socket.io instance. 最简单的解决方案是导出一个新模块并将其传递给socket.io实例。 So in your app.js you have : 所以在你的app.js中你有:

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. 现在需要一个新模块并将其传递给socketio参考。 Add this new line (in app.js) to do so : 添加此新行(在app.js中)来执行此操作:

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

Then create a new file in your path/to/your/socketio/controller called socketio.js 然后在你的path/to/your/socketio/controller创建一个名为socketio.js的新文件

And finally in the socketio.js file, export your new module : 最后在socketio.js文件中,导出新模块:

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 看看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. 至于绕过必须通过io对象。 You have a few options, which may or may not be "best" depending on who you ask. 您有几个选项,根据您的要求,可能会也可能不会“最佳”。

  • Make io or app global. 使ioapp全球化。 (some people freak out over globals) (有些人对全局变得惊慌失措)
  • Use module.exports and require the object in the other file. 使用module.exportsrequire另一个文件中的对象。 (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. 传递io对象可能是最简单的方法,但你确实有选择。

socket.io doesn't work with routes, it works with sockets. socket.io不适用于路由,它适用于套接字。

You add this code to app.js or a separate file which you include in app.js: 您将此代码添加到app.js或您在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: 您的更新路线仅使用javascript呈现html文档,其中包含:

<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. 因此,一旦页面呈现并完成,client-javascript将打开一个到服务器的套接字并接收其他数据。

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). 我使用过Expressjs的中间件路由器(我使用的是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')中写下最后一个路径:

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

});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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