如何使用NodeJS从多个路由发送socket.io消息

时间:2018-06-28 14:36:12

标签: node.js socket.io

我正在使用socket.io在客户端和NodeJS HTTP服务器之间发送和接收消息。到目前为止,它可以正常工作,因为所有代码都在app.js主文件中,如下所示:

let express = require('express')
let app = express();

let http = require('http');
let server = http.Server(app);

let socketIO = require('socket.io');
let io = socketIO(server);

io.on('connection', (socket) => {
    console.log('New user connected');

    socket.on('new-message', (message) => {
        console.log(message);

        io.emit('new-message', message);
    });
});

但是现在我有这种情况:

  • 当用户从客户端应用请求/compile/save路由时,服务器需要执行一些操作(每个操作最多需要2s),我想保留他通过socket.io通知发送消息以显示每个操作的结果。这是一个路由处理程序示例:

routes / compile.js

var express = require('express');

var router = express.Router();

router.get('/compile', (req, res, next) => {
    // DO THE OPERATIONS

    // For each operation, send a socket.io message to the client with the result
});

每个客户端的socket是在连接到服务器(io.on('connection', (socket) => {)时在主文件中获得的,所以如何在路由中使用它?

希望我解释得很好,nodeJS / socket.io的组合让我很惊讶...谢谢!

2 个答案:

答案 0 :(得分:1)

一种简单的方法是将用户加入特定渠道,然后发布到该特定渠道。

io.on('connection', (socket) => {
    console.log('New user connected');

    const userId = getUserIdSomehow(); // logged user, ip, cookie, or whatever you like
    socket.join(userId); 

    socket.on('new-message', (message) => {
        console.log(message);

        io.emit('new-message', message);
    });
});

快速路线

router.get('/compile', (req, res, next) => {
    // DO THE OPERATIONS
    const userId = getUserIdSomehow(); // ip, cookie, or whatever you like
    io.to(userId).emit('some-event', 'some-data');
    // For each operation, send a socket.io message to the client with the result
});

您将需要将io实例传递到您的快速路由模块。有多种方法,请检查以下问题:

What is the best way to pass common variables into separate modules in Node.js?


另一种方法是使用Cookie或自定义标头在HTTP请求中发送socketId。

客户端

socket.on('connect', function() {
    // Save this session Id, and use it on every request
    const sessionid = socket.socket.sessionid;
    setCookie('socketId', sessionId); // implement setCookie
});

快速路线

router.get('/compile', (req, res, next) => {
      // DO THE OPERATIONS
      const userId = req.cookies.socketId;
      io.to(userId).emit('some-event', 'some-data');
      // For each operation, send a socket.io message to the client with the result
 });
  

Socket.IO中的每个Socket都是由随机的,不可猜测的,   唯一标识符Socket#id。为了您的方便,每个插座   自动加入此ID标识的房间

这种方式的缺点是,如果套接字连接断开,或者用户离开,则socketId将更改,并且您将无法发出该消息。如果您可以识别并保持用户的身份,则建议采用第一种方法。

答案 1 :(得分:0)

根据Marcos的建议,这是我为解决该问题所做的事情:

app.js

let socketIO = require('socket.io');
let io = socketIO(server);

// ROUTES
let compileRoute = require('./routes/compile')(io);  // Inject the Socket IO object into the routes module

app.use('/compile', compileRoute);

routes / compile.js

module.exports = function(io) {
    router.post('/', (req, res, next) => {
        var body = req.body;

        var sid = body.socketId;  // Socket ID from the client

        // OPERATION LOOP

        // Use the injected Socket IO object and the socket ID received from the client
        // to send the result messages
        io.to(sid).emit('new-message', 'Operation result');
    });

    return router;
};

角度组件

public doCompile() {
    const body = {
        // Obtain the socket ID from the service (basically, it returns this.socket.id)
        socketId: this.socketService.getSocketId()
    };

    // Send the HTTP request with the socket id in the body
    this.httpClient.post('http://localhost:2999/compile', body).subscribe(
}

现在,我必须管理可能的套接字断开连接,以便在套接字服务中重新分配新的套接字ID,但这是另一个主题:)

干杯