Nodejs,在MongoStore中保持套接字io连接

时间:2013-09-18 22:59:01

标签: node.js session socket.io

在nodejs-express app中,在server.js文件中我设置了socket-io连接。 它可以正常做这样的事情

var server = require('http').createServer(app)
var io = require('socket.io').listen(server);
io.sockets.on('connection', function (socket) {

    // how can I save globally this 'socket'?

});

我想在server.js文件中全局保存这个'socket',因此,能够在项目的任何地方使用它。像这样:

app.get('/on', function(req, res){
    socket.on('test', function (data) {
        console.log(data);
    });
});
app.get('/emit', function(req, res){
    socket.emit('test', "ciao");
});

我红了有一种方法可以在会话中保存'socket'连接。我的会话设置:

app.configure(function(){
    // ....
    app.use(express.cookieParser(SITE_SECRET));
    app.use(express.session({
        secret : 
        ,store  : new MongoStore({
        mongoose_connection : mongoose.connection
        ,db: mongoose.connections[0].db
    })
    ,cookie: { maxAge: new Date(Date.now() + (1000*60*60*24*30*12)) }
    }));
     ...
});

有什么好办法吗?

此外,在进行了此保存之后,如果连接未打开,如何使用socket.on()和socket.emit()加载第一页?

1 个答案:

答案 0 :(得分:3)

您可能听到的不是将套接字保存到会话中,而是通过其会话cookie引用套接字,该cookie在套接字授权过程中传递给服务器。在授权期间,这是传递给服务器的对象类型的示例:

{
  headers: req.headers,       // <Object> the headers of the request
  time: (new Date) +'',       // <String> date time of the connection
  address: socket.address(),  // <Object> remoteAddress and remotePort object
  xdomain: !!headers.origin,  // <Boolean> was it a cross domain request?
  secure: socket.secure,      // <Boolean> https connection
  issued: +date,              // <Number> EPOCH of when the handshake was created
  url: request.url,           // <String> the entrance path of the request
  query: data.query           // <Object> the result of url.parse().query or a empty object
}

我们感兴趣的是headers属性,我们可以在其中找到连接套接字的会话cookie。然后我们在授权期间解析cookie:

// pass same objects from Express to Socket.IO so they match
var parseCookie = express.cookieParser(SITE_SECRET);
var store = new MongoStore({
  mongoose_connection: mongoose.connection,
  db: mongoose.connections[0].db
});

io.configure(function() {
  io.set('authorization', function(handshake, callback) {
    if (handshake.headers.cookie) {
      parseCookie(handshake, null, function(err) {
        // we used the signedCookies property since we have a secret
        // save the session ID to the socket object, we can access it later
        handshake.sessionID = handshake.signedCookies['connect.sid'];

        store.get(handshake.sessionID, function(err, session) {
          // we have the same Express session, reference it
          socket.session = session;
          callback(null, true);
        });
      });
    } else {
      // they client has no session yet, don't let them connect
      callback('No session.', false);
    }
  });
});

app.use(parseCookie);
app.use(express.session({
  secret: SITE_SECRET,
  store: store,
  cookie: {maxAge: new Date(Date.now() + (1000*60*60*24*30*12))}
}));

然后,一旦我们保存了会话ID,我们就可以使用典型的连接事件:

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

var clients = {};
io.sockets.on('connection', function (socket) {
  // save to a global object
  var session = socket.handshake.sessionID;
  clients[session] = socket;

  socket.on('disconnect', function() {
    delete clients[session];
  });
});

然后我们通过cookie签名进行全局引用。然后我们可以像这样访问套接字:

app.get('/path', function(req, res) {
  var socket = clients[req.sessionID];
  socket.emit('Socket client accessed route.');
});

请记住,对于具有多个选项卡的客户端,您可能必须在全局逻辑中添加一些逻辑,这将导致两个套接字具有相同的授权cookie。

关于使用socket.on()socket.emit()的问题,在建立连接之前不能使用它,因为套接字本身不存在。如果要向所有连接的客户端发送消息,则应该只使用全局io.sockets对象。这将更像io.sockets.emit()