在快速路由文件中使用socket.io

Mat*_*kin 17 sockets node.js socket.io

我正在尝试将Socket.io与Node.js一起使用并发送到路由逻辑中的套接字.

我有一个相当标准的Express 3设置,其中包含一个位于路由中的server.js文件,然后我有一个index.js,它位于路径文件夹中,用于导出站点的所有页面/可公开访问的功能.所以他们看起来像:

exports.index = function (req, res) {
    res.render('index', {
        title: "Awesome page"
    });
}; 
Run Code Online (Sandbox Code Playgroud)

与server.js中定义的路由类似:

app.get('/',routes.index);
Run Code Online (Sandbox Code Playgroud)

我假设我必须在server.js中创建socket.io对象,因为它需要服务器对象,但是如何访问该对象并从index.js导出函数向它发出?

aar*_*sil 88

现在有一种更好的方法可以使用Express 4.0.

您可以使用app.set()来存储io对象的引用.

基本配置:

var app = require('express')();
var server = app.listen(process.env.PORT || 3000);
var io = require('socket.io')(server);
// next line is the money
app.set('socketio', io);
Run Code Online (Sandbox Code Playgroud)

内部路由或中间件:

exports.foo = function(req,res){
    // now use socket.io in your routes file
    var io = req.app.get('socketio');
    io.emit('hi!');
}
Run Code Online (Sandbox Code Playgroud)

关于信息app.set()app.get()低于:

app.set(名称,值)

将设置名称指定给值.您可以存储所需的任何值,但可以使用某些名称来配置服务器的行为.这些特殊名称列在应用程序设置表中.

调用app.set('foo', true)Boolean属性与调用相同app.enable('foo').同样,调用app.set('foo', false) Boolean属性与调用相同app.disable('foo').

使用检索设置的值app.get().

资料来源:https: //expressjs.com/en/api.html#app.set

  • 这应该是批准的答案.谢了哥们. (7认同)
  • 有人已经使用过这种方法吗?我对此有疑问。当页面重新加载或套接字重新连接时,所有的发射都由袜子两次,塞得更紧等等。。。对此没有任何解决方法(我都找不到)。在快速路由中使用socketio似乎是不可能的 (2认同)
  • @marcvander你不能在一个端点内部监听,你只能在app.js或server.js上监听,但你可以在路由文件内发出 (2认同)

hex*_*ide 19

您可以将路径文件设置为函数,并在需要该文件时传递Socket.IO对象.

module.exports = function(io) {
  var routes = {};
  routes.index = function (req, res) {
    io.sockets.emit('payload');
    res.render('index', {
      title: "Awesome page"
    });
  };
  return routes;
};
Run Code Online (Sandbox Code Playgroud)

然后需要这样的路线:

var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
var routes = require('./routes')(io);
Run Code Online (Sandbox Code Playgroud)

  • 好吧,这确实需要一些重构.我希望有一个更清洁的方式 (2认同)
  • 这个解决方案很好,但如果你想看到一个类似的方法,一点点清洁和直观检查这个答案我找到了Logan Tegman http://stackoverflow.com/questions/29872317/express-4-routes-using-socket -io (2认同)

joh*_*ohn 13

aarosil的答案很棒,但我遇到了与Victor一样的问题,使用这种方法管理客户端连接.对于客户端上的每次重新加载,您将在服务器上获得尽可能多的重复消息(第二次重新加载= 2次重复,第三次= 3次重复等).

扩展了aarosil的答案,我使用这种方法在我的路由文件中使用套接字对象,并管理连接/控制重复消息:

内部服务器文件

// same as aarosil (LIFESAVER)
const app = require('express')();
const server = app.listen(process.env.PORT || 3000);
const io = require('socket.io')(server);
// next line is the money
app.set('socketio', io);
Run Code Online (Sandbox Code Playgroud)

内部路线文件

exports.foo = (req,res) => {

   let socket_id = [];
   const io = req.app.get('socketio');

   io.on('connection', socket => {
      socket_id.push(socket.id);
      if (socket_id[0] === socket.id) {
        // remove the connection listener for any subsequent 
        // connections with the same ID
        io.removeAllListeners('connection'); 
      }

      socket.on('hello message', msg => {
        console.log('just got: ', msg);
        socket.emit('chat message', 'hi from server');

      })

   });
}
Run Code Online (Sandbox Code Playgroud)


Ema*_*aid 8

只使用有什么问题

global.io = require('socket.io').listen(server);
Run Code Online (Sandbox Code Playgroud)


jme*_*e11 6

在这里添加超级晚,但我想访问我的路由中的套接字,并且特别想在保存到数据库后广播一条消息。我使用@aarosil 提供的答案来设置/获取 io 对象,在连接时向每个客户端发送其套接字 id,然后在路由中使用套接字 id 来socket.broadcast.emit()代替io.emit().

在服务器中:

const io = require('socket.io')(server)
app.set('socketio', io)

io.on('connect', socket => {
  socket.emit('id', socket.id) // send each client their socket id
})
Run Code Online (Sandbox Code Playgroud)

我发送每个请求的套接字 ID,然后我可以在我的路由中执行以下操作:

router.post('/messages', requireToken, (req, res, next) => {

  // grab the id from the request
  const socketId = req.body.message.socketId

  // get the io object ref
  const io = req.app.get('socketio') 

  // create a ref to the client socket
  const senderSocket = io.sockets.connected[socketId]

  Message.create(req.body.message)
    .then(message => {

      // in case the client was disconnected after the request was sent
      // and there's no longer a socket with that id
      if (senderSocket) {

        // use broadcast.emit to message everyone except the original
        // sender of the request !!! 
        senderSocket.broadcast.emit('message broadcast', { message })
      }
      res.status(201).json({ message: message.toObject() })
    })
    .catch(next)
})

Run Code Online (Sandbox Code Playgroud)