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

Posted

技术标签:

【中文标题】ExpressJS - 带有路由分离的 Socket.IO【英文标题】:ExpressJS - Socket.IO with Route Separation 【发布时间】:2012-09-16 00:18:56 【问题描述】:

我正在尝试了解 ExpressJS 和 Socket.IO。我的路线在一个单独的文件中,我包含在我的 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');

但是,当我尝试从我的一条路线发出事件时,我没有引用 socket.io。

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

我明白为什么这可能不可用。相反,我不明白处理 socket.io 的最佳方法是从 app.js 以外的另一个文件。我在看this question(见里卡多的回答),但我仍然不清楚。理想情况下,我想避免这样做:

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

【问题讨论】:

你可以避免使用 http 模块,尽管 socket.io 需要一个 http 服务器,你可以从 express 依赖项 (3.xx) 中调用它: var app = express(), server = app.听(3000),io = socket.listen(服务器); 更新:看看feathers.js 【参考方案1】:

好吧,您实际上并不需要 express.io。最简单的解决方案是导出一个新模块并将其传递给 socket.io 实例的引用。 所以在你的 app.js 中你有:

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

现在需要一个新模块并将 socketio 引用传递给它。添加这个新行(在 app.js 中)这样做:

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

然后在 path/to/your/socketio/controller 中创建一个名为 socketio.js 的新文件

最后在 socketio.js 文件中,导出你的新模块:

module.exports = function(io) 

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

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

            console.log(data);

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

你去吧!

【讨论】:

感谢您的示例。您能否进一步详细说明不需要快递?我一直在思考实现纯基于套接字的解决方案的方法。 这个“sockets.js”模块策略在 Github 上看起来很流行,但对于我来说——我无法理解路由文件(例如 ./routes/myRoutes)如何访问该模块(sockets.js)稍后。 :(【参考方案2】:

查看express.io

它具有实时请求路由,以及许多其他有用的功能。

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

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

app.listen(7076)

至于必须传递io 对象。您有几个选择,可能是“最好的”,也可能不是“最佳”,具体取决于您询问的对象。

ioapp 设为全局。 (有些人被全局变量吓坏了) 在另一个文件中使用module.exportsrequire 对象。 (如果处理不当会导致循环依赖问题)

传递io 对象可能是最干净最简单的方法,但您确实有选择。

【讨论】:

死链接。已弃用? express.io 链接失效,正在重定向到 express-io.org【参考方案3】:

socket.io 不适用于路由,它适用于套接字。

您将此代码添加到 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);
    
  );
);

您的更新路线仅使用 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>

所以一旦页面被渲染并完成,client-javascript 将打开一个到服务器的套接字并接收额外的数据。

见more examples here.

免责声明:代码从头开始编写,未经测试。

【讨论】:

明白。我的 express 应用程序仅充当一个安静的 API,因此除了默认设置之外,没有太多的视图。一旦记录发生更改,我想发出一个事件 - 只是不确定我应该从服务器(保存后)还是客户端发送通知。 您可以使用 .post-route in express 和 jQuery/ajax 解决方案来做到这一点。可能比 socket.io 更好。【参考方案4】:

最好的方法是使用闭包。例如:

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

还有:

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

【讨论】:

【参考方案5】:

我用过Expressjs的中间件路由器(我用的是4.x)。

在外部路由文件中,我放置了“下一个”对象:

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

在主文件中,我在 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' );
    );

);

【讨论】:

以上是关于ExpressJS - 带有路由分离的 Socket.IO的主要内容,如果未能解决你的问题,请参考以下文章

ExpressJS 路由器规范化/规范 url

ExpressJS - 嵌套/链接资源的 RESTful 路由设计

在运行时添加路由 (ExpressJs)

Expressjs - 所有路由都是 404

NodeJs + ExpressJs 应用程序路由奇怪的行为

ExpressJS:如何忽略路由中的公共静态文件?