【问题标题】:Implement socket.io in node.js application controller在 node.js 应用程序控制器中实现 socket.io
【发布时间】:2022-01-16 23:58:29
【问题描述】:

下午好。我是在 node.js 中编程套接字的新手,我需要在我的应用程序的控制器中实现 socket.io。我的架构如下:

启动服务器的文件是index.js

const express = require('express');
const app = express();
const port = 3000;
const socketRouter = require('./routes/socket')

app.use(express.json());
  
//Route
app.use('/socket', socketRouter);

app.listen(port, () => {
    console.log(`Server connection on  http://127.0.0.1:${port}`);  // Server Connnected
});

我定义路由的文件是socket.js

const { Router } = require('express');
const { showData } = require('../controllers/socket');

const router = Router();

router.post('/send-notification', showData);

module.exports = router;

我的控制器是:

const { response } = require('express');

const showData = (req, res = response) => {
    const notify = { data: req.body };
    //socket.emit('notification', notify); // Updates Live Notification
    res.send(notify);
}

module.exports={
    showData
}

我需要在这个控制器中实现 socket.io 才能从它发出,但我不能让它工作。你能告诉我怎么做吗? 非常感谢

澄清:如果我在主文件中实现 socket.io,它可以工作,但我想要一些顺序和分开的东西。它是这样工作的:

const express = require('express');
const app = express();
const port = 3000;

app.use(express.json());

app.post('/send-notification', (req, res) => {
    const notify = { data: req.body };
    socket.emit('notification', notify); // Updates Live Notification
    res.send(notify);
});

const server = app.listen(port, () => {
    console.log(`Server connection on  http://127.0.0.1:${port}`);  // Server Connnected
});

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

socket.on('connection', socket => {
    console.log('Socket: client connected');
});

【问题讨论】:

  • 在您的app.post() 中显示socket.emit(),您要向哪个套接字发射?而且,POST 是来自浏览器中的表单提交还是来自网页中的 Javascript?
  • 一个 post 请求来自 localhost:3000/send-notification 路由,对象“data”作为参数来自网络上的表单。然后,在收到所述请求后,向所有正在监听“通知”事件的客户端发出发射。但我不想在 index.js 中有这个逻辑,而是在一个单独的控制器中,如开头所示

标签: node.js express socket.io


【解决方案1】:

将您的 socket.io 代码移动到它自己的模块中,您可以在其中导出一个共享 socket.io 服务器实例的方法:

// local socketio.js module

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

let io;
modules.exports = {
   init: function(server) {
       io = socketio(server);
       return io;
   },
   getIO: function() {
       if (!io) {
          throw new Error("Can't get io instance before calling .init()");
       }
       return io;
   }
}

然后,在你的主应用文件中初始化 socketio.js 模块:

const express = require('express');
const app = express();
const port = 3000;


app.use(express.json());
  
const server = app.listen(port, () => {
    console.log(`Server connection on  http://127.0.0.1:${port}`);  // Server Connnected
});

// initialize your local socket.io module
const sio = require('./socketio.js');
sio.init(server);

// now load socket.io dependent routes
// only after .init() has been called on socket.io module
const socketRouter = require('./routes/socket')
app.use('/socket', socketRouter);

然后,在任何你想访问 socket.io 服务器实例的地方,你都可以 require("./socketio.js") 并使用.getIO() 方法获取socket.io 实例:

// use correct path to socketio.js depending upon where this module 
// is located in the file system
const io = require("../../socketio.js").getIO();

// some Express route in a controller
const showData = (req, res) => {
    const notify = { data: req.body };

    // send notification to all connected clients
    io.emit('notification', notify);
    res.send(notify);
};

module.exports= {
    showData
};

注意:服务器上典型的 socket.io 使用约定是使用io 作为服务器实例,socket 作为单独的客户端连接套接字实例。请不要尝试同时使用socket。这清楚地表明io.emit(...) 正在尝试发送到所有连接的客户端,而socket.emit() 正在尝试发送到单个连接的客户端。

还请注意,如果您的路由是由浏览器本身发送表单帖子的表单帖子触发的,那么该特定客户端将不会收到来自该表单帖子路由的io.emit(...) 完成的结果,因为该浏览器将在根据表单发布的响应加载新网页的过程,并将破坏其当前的 socket.io 连接。如果表单发布完全通过 Javascript 使用 Ajax 调用完成,则该网页将保持活动状态并接收io.emit(...) 的结果。

【讨论】:

    【解决方案2】:

    如果您想按功能分开套接字消息和 REST 端点,或者您选择组织它,您可以在其他文件中使用相同的 socketapp(如果您还需要公开 API)。以下是如何做到这一点的示例:

    创建一个新文件,比如说controller1.js

    function initialize(socket, app) {
        socket.on('some-socket-message', socket => {
            // Whatever you want to do
        });
        
        app.get('/some-endpoint', (req, res) => {
            // whatever you want to do
        });
    }
    
    
    module.exports = {initialize}
    

    然后将以下内容添加到您的controller.js

    const controller1 = require('path/to/controller1');
    
    ...
    
    // At some point after socket and app have been defined
    controller1.initalize(socket, app);
    

    这将是根据需要分离控制器的基础,同时在所有控制器中仍使用相同的套接字连接和 API 端口。您还可以将initialize 方法重构为不同的方法,但这取决于您自己的判断以及您希望如何命名函数等。它也不需要称为initalize,这只是我的偏好名称.

    【讨论】:

    • 您好 Sal,感谢您的回答,但我不清楚。我在哪里进行套接字的初始配置?
    • 您提到socket.io 连接已经有效,我没有关注这个问题
    • 你好。它可以工作,但将所有配置放在服务器的主文件(index.js)中,但我不想在那里拥有所有东西。我想要实现的是在控制器中进行发射
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-20
    • 2020-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多