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
对象。您有几个选择,可能是“最好的”,也可能不是“最佳”,具体取决于您询问的对象。
io
或app
设为全局。 (有些人被全局变量吓坏了)
在另一个文件中使用module.exports
和require
对象。 (如果处理不当会导致循环依赖问题)
传递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 - 嵌套/链接资源的 RESTful 路由设计