33

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

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

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

使用 server.js 中定义的路由,例如:

app.get('/',routes.index);

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

4

7 回答 7

133

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

内部路由或中间件:

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

关于app.set()app.get()的信息如下:

app.set(名称,值)

将设置名称分配给值。您可以存储任何您想要的值,但某些名称可用于配置服务器的行为。这些特殊名称列在应用设置表中

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

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

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

于 2015-07-07T18:58:30.480 回答
30

您可以将路由文件设置为函数,并在需要文件时传递 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;
};

然后需要这样的路线:

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);
于 2013-09-17T17:36:59.417 回答
24

aarosil 的回答很棒,但我遇到了与 Victor 相同的问题,即使用这种方法管理客户端连接。对于客户端上的每次重新加载,您会在服务器上获得尽可能多的重复消息(第 2 次重新加载 = 2 次重复,第 3 次 = 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);

内部路由文件

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

      })

   });
}
于 2017-04-28T17:39:13.057 回答
8

在这里添加超级晚,但我想访问我的路由中的一个套接字,并且特别想在保存到数据库后广播一条消息。我使用@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
})

我使用每个请求发送套接字 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)
})

于 2019-08-31T11:54:13.700 回答
6

只使用有什么问题

global.io = require('socket.io').listen(server);
于 2017-02-16T22:12:18.147 回答
1

在服务器文件中,

    const app = express();
    const server = require("http").createServer(app);
    
    const io = require("socket.io")(server);
    io.on("connection", (socket) => {
      app.set("socket", socket);
    });

在任何控制器内部,

     const socket = req.app.get("socket");
     socket.emit(customerId, { test: "something" });
于 2021-08-16T11:36:20.123 回答
0

module.parent.exports.server如果您在父模块中导出服务器,也可以使用。

于 2017-05-18T18:16:29.347 回答