【问题标题】:Problem with socket when using it in express在 express 中使用套接字时出现问题
【发布时间】:2019-11-07 20:50:13
【问题描述】:

我的程序中的套接字有问题。导出“io”连接,虽然我可以从普通程序的任何部分广播(仅通过引用“io”),但我不能使用“socket”并用它广播,除非它在“io”的同一连接内。我想知道如何从程序的任何其他部分使用套接字,例如“socket.emit()”或“socket.broadcast.emit”等函数。或者如何调用这个。

这是我的 index.js:

const express = require('express');
const restApi = express();
const cors = require('cors');
const server = require('http').createServer(restApi);
const rutas = require('./src/routes/Routes.js');
const io = require('./src/socket/SocketManager.js');
io.attach(server);

restApi.use(express.json());
restApi.use(express.static('public'));
restApi.use(cors());
restApi.options('*', cors());

server.listen(4040, () => console.log('Listening server in port 4040'));

restApi.all('/*', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  next();
});

restApi.use('/api',rutas);

我的 managersocket.js:

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

io.on('connection', function (socket) {
    console.log('NUEVA CONEXION: ',socket.id);
    socket.emit('recoger',socket.id);
});

module.exports = io;

这是我想使用套接字或至少调用函数的地方。

和 User.js:

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

var RouterUser = function(){

  this.practicafuncion = function (req,res){
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    console.log('probando entrar por rest y que salga un mensaje por socket');
    res.send({
      status:'Aprobado',
      msj:'Enviado por rest'
    });
//this works correctly.     io.sockets.emit('mensaje','**MENSAJESERVIDORPORSOCKET**');
//This is not the problem when using "socket".   socket.broadcast.emit('mensaje','**MENSAJESERVIDORPORSOCKET**');
  };
}

module.exports = function(){
  var instancia = new RouterUser();
  return instancia;
};

同样是整个代码所在的存储库

https://github.com/proxirv/Socket.io-router

【问题讨论】:

    标签: javascript node.js express socket.io router


    【解决方案1】:

    socket 是一个临时对象,仅在一个特定客户端连接期间存在。而且,可能有无数个(每个连接的客户端一个或多个)。因此,您不只是导出一个 socket 或将其填充到全局中并尝试在任何地方使用它。

    因此,如果您要尝试为刚刚收到 http 请求的用户访问 socket.io 连接,那会有点复杂,并且有几种不同的方法来处理它。

    我以前使用过的一种方法如下所示:

    const express = require('express');
    const app = express();
    const server = app.listen(80);
    const io = require('socket.io')(server);
    const expsession = require('express-session');
    const path = require('path');
    
    // install session middleware
    const sessionMiddleware = expsession({
      secret: 'random secret',
      saveUninitialized: true,
      resave: true
    });
    
    // run session middleware for regular http connections
    app.use(sessionMiddleware);
    
    // run session middleware for socket.io connections
    io.use(function(socket, next) {
        sessionMiddleware(socket.request, socket.request.res, next);
    });
    
    // when a socket.io connection connects, put the socket.id into the session
    // so it can be accessed from other http requests from that client    
    io.on('connection', function(socket) {
        // socket.handshake.headers
        console.log(`socket.io connected: ${socket.id}`);
    
        // save socket.io socket in the session
        console.log("session at socket.io connection:\n", socket.request.session);
        socket.request.session.socketio = socket.id;
        socket.request.session.save();
    });
    
    // any arbitrary express route definition
    // Note: you can't send socket.io data in a request that loads an HTML page
    //       because that client hasn't yet established the socket.io connection
    //       for that page.  The socket.io connections will be created after
    //       the browser loads this page.
    app.get("/", function(req, res) {
        const session = req.session;
        console.log("\n\npage load\n---------------------------\n");
        console.log("session:\n", session);
        res.sendFile(path.join(__dirname, "socket-io-session.html"));
    });
    
    // Upon an API call from a page that already has a socket.io connection,
    // respond to the API call and send something to that page's socket.io socket
    app.get("/api/test", function(req, res) {
        const session = req.session;
        io.sockets.connected[session.socketio].emit('show', "sending some data");
        console.log("session:\n", session);
        console.log("session.socketio:\n", session.socketio);
        res.json({greeting: "hello"});
    });
    

    以下是该概念的步骤:

    1. 为常规 http 连接设置快速会话。这为您提供了一个存储属于某个特定客户端(由 cookie 键入)的内容的地方
    2. 为 socket.io 连接设置 express-session,以便您还可以访问 socket.io 连接中的 express-session 数据。
    3. 当发生 socket.io 连接时,将 socket.id 存储在会话中。这使得 socket.id 可用于来自该特定客户端的未来 http 请求
    4. 当将来某个 HTTP 请求来自该客户端时,您可以进入会话,获取 socket.id 值(它只是一个字符串),然后使用它来获取该用户的套接字,一旦您拥有套接字,您可以使用socket.emit() 仅向该用户发送数据。

    如果您没有其他原因使用 express-session,您也可以在 socket.io 连接连接时将 socket.id 单独放入 cookie 中,然后在期间从 cookie 中获取 socket.id你的 http 请求。

    【讨论】:

    • 首先,感谢您抽出宝贵的时间。你的澄清很好,但在我的情况下,我必须遵循这个架构,在 index.js 以外的文件中提出 io。在您的实例所在的 socketmanager.js 文件中引发 io。在我的 index.js 中,我调用了我的路由所在的文件,然后我从那里调用了一个名为 user.js 的文件中的函数,该文件就是逻辑所在的位置。我需要能够从 user.js 访问 io 和 socket,要么在那里使用它,要么在帖子末尾调用 socketmanager.js 中的 io 内部的函数我放了存储库地址
    • @proxirv - 这是中间件的架构,它使 socket.io 套接字在任何文件中的任何 Express 请求处理程序中都可用,供这些请求处理程序使用。如何在文件中拆分内容取决于您。这是您可以使用的结构。如果io 在不同的文件中,那么您只需导出io,以便在其他文件中使用它。这只是一个常规的导出/导入设计实现。这是在该用户的 Express 请求处理程序期间获取用户的 socket.io 连接可用的困难部分。不知道你还问什么。
    • @proxirv - 这回答了你的问题吗?如果是这样,您可以通过单击答案左侧的复选标记在此处向社区表明这一点。这也将为您在 stackoverflow 上赢得一些声誉点,以遵循正确的程序。如果这没有回答您的问题,请评论您仍然对问题的哪一部分感到困惑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 1970-01-01
    • 2017-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多