提问者:小点点

如何从Express 4路由中使用socket.io向连接的套接字发出事件?


这是一个别人问过的问题,但我无法从他们给出的答案中获益,因为我有不同的快速设置。

我已经实现了socket.io,并在我的服务器上以一种简单的方式工作。它的工作原理如下:

bin/www中:

#!/usr/bin/env node
var debug = require('debug')('gokibitz');
var app = require('../../server');

app.set('port', process.env.PORT || 3000);

var server = app.listen(app.get('port'), function() {
    debug('Express server listening on port ' + server.address().port);
});

var io = require('socket.io').listen(server);

io.on('connection', require('../routes/socket.js'));

我的所有路由和其他快速设置都在../../server.js中。

var routes = require('./server/routes/index');
var user = require('./server/routes/user');
...

app.use('/', routes);
app.use('/api/user/', user);
...
app.use('*', routes);

然后在。。/routes/socket.js中,我得到了这个样板:

module.exports = function (socket) {
    socket.emit('send:news', { hello: 'world' });

    setInterval(function () {
        socket.emit('send:time', {
            time: (new Date()).toString()
        });
    }, 1000);

    return socket;
};

我得补充一句,这工作得很好。但是现在我希望能够在我的普通Express应用程序中从各种路由发出事件,而我却始终无法找到正确的方法来获取对所需socket对象的引用。

示例:当一个用户发表评论时,我想向所有连接的用户发出一个事件,通知他们新的评论。从我的routes文件(./server/routes/user.js)中,我如何访问我需要发出事件的对象?

以下是路由文件中相关位的概要:

var express = require('express');
var router = express.Router();

router.post('/', function (req, res) {
  ...
});

module.exports = router;

我唯一可以访问它的地方是在../routes/socket.js文件中,这是没有用的。

在传入任何io或套接字对象之前,所有路由都在app.js中设置。

我是否应该能够require('socket.io')并以某种方式使用它来发射到所有连接的套接字?

是否有一种明智的方法将连接的套接字存储在。。/routes/socket.js上,以便可以从其他路由要求和发出它?

有人能把我引向正确的方向吗?


共3个答案

匿名用户

我最终能够使用以下示例来实现这些操作:https://github.com/expressjs/generator/issues/45#issuecomment-53719435

我创建了一个名为server/io.js的新文件:

var io = require('socket.io')();

io.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});

module.exports = io;

然后我将server/bin/www更新为:

#!/usr/bin/env node
var debug = require('debug')('gokibitz');
var app = require('../../server');
var io = require('../io');

app.set('port', process.env.PORT || 3000);

var server = app.listen(app.get('port'), function() {
    debug('Express server listening on port ' + server.address().port);
});

io.attach(server);

然后,在我的路由中,我使用这个:

var io = require('../io');
...
io.emit(...);

至少,我缺少的是单独创建IO对象,返回正确的对象,然后使用bin/www内的IO.attach(server)在正确的位置启动它。

希望这能帮助其他人步我的后尘。

匿名用户

我想你混淆了这些概念。IO库与客户端使用或模拟websocket(双向套接字),与路由无关。

您可以使用io对象向所有套接字发送通知:

io.emit('message_to_all', true);

您必须在io.sockets上创建一个数组,包含所有套接字。

您可以使用名称空间或房间,我建议您学习以下文档:

http://socket.io/docs/rooms-and-namespaces/#

添加内容:

如果要向同一路由中的所有人发送消息,可以加入路径名称相同的通道。

例如,在客户端中:

var socket = io(window.location.href); // Or route..

和服务器:

var nsp = io.of('/the/specific/route');
nsp.on('connection', function(socket){
  // ...
});
nsp.emit('message_to_all_in_route', data);

关于最后一个问题编辑:

您可以使用Express中间件API将请求或响应对象中的io对象发送到路由:

例如:

#!/usr/bin/env node
var debug = require('debug')('gokibitz');
var app = require('../../server');

app.set('port', process.env.PORT || 3000);

var server = app.listen(app.get('port'), function() {
    debug('Express server listening on port ' + server.address().port);
});

var io = require('socket.io').listen(server);

app.use(function (req, res, next) {
  res.io = io;
  next();
});

io.on('connection', require('../routes/socket.js'));

在路线中:

route.post('/post/:id/comments', function (req, res) {

   // Do your logic

  var postio = res.io.of('/post/' + req.params.id);
  postio.emit('new_comment', commentData);

});

匿名用户

正如我在评论中所说的,您可以向所有连接的客户端发送:

io.emit(msg, data);

这将需要访问您在第一个模块中创建的IO对象。与您的模块和routes模型共享该信息的通常方法是从routes模块导出一个方法,该方法允许您将IO对象传递给routes模块,然后在您在routes模块中进行required操作并创建了IO对象之后,您只需调用该方法就可以将IO对象传递给routes模块,routes模块可以将其保存在本地以备将来使用。

IO只是一个共享对象,就像app对象一样。如果您希望一个模块能够使用共享对象,通常的方式是调用该模块中的某个方法,与它共享一些随后它可以使用的对象。