简体   繁体   English

在 node.js 应用程序 controller 中实现 socket.io

[英]Implement socket.io in node.js application controller

good afternoon.下午好。 I am new to programming sockets in node.js and I need to implement socket.io in a controller of my application.我是在 node.js 中编程 sockets 的新手,我需要在 my 应用程序的 Z594C103F2C6E004C3D8AB05C 中实现 socket.io。 The architecture I have is the following:我拥有的架构如下:

The file that starts the server is index.js启动服务器的文件是 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
});

The file where I define the routes is socket.js我定义路由的文件是 socket.js

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

const router = Router();

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

module.exports = router;

And my controller is:而我的 controller 是:

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
}

I need to implement socket.io in this controller to be able to emit from it but I can't get it to work.我需要在这个 controller 中实现 socket.io 才能从中发射,但我无法让它工作。 Could you tell me how to do it?你能告诉我怎么做吗? Thanks a lot非常感谢

CLARIFICATION: if I implement socket.io in the main file it works, but I want to have some order and separate things.澄清:如果我在主文件中实现 socket.io 它可以工作,但我想要一些顺序和单独的东西。 This is how it works:这是它的工作原理:

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

You can use the same socket and app (if you need to expose APIs as well) in other files if you want to separate socket messages and REST endpoints by functionality or however you choose to organize it.如果您想按功能分开套接字消息和 REST 端点,或者您选择组织它,您可以在其他文件中使用相同的socketapp (如果您还需要公开 API)。 Here's an example of how this can be done:以下是如何做到这一点的示例:

Create a new file, let's say controller1.js :创建一个新文件,比如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}

And then add the following to your controller.js然后将以下内容添加到您的controller.js

const controller1 = require('path/to/controller1');

...

// At some point after socket and app have been defined
controller1.initalize(socket, app);

This will be the bases of separating your controller however you want, while still using the same socket connection and API port in all of your controllers.这将是根据需要分离 controller 的基础,同时在所有控制器中仍使用相同的套接字连接和 API 端口。 You can also refactor the initialize method into different methods, but that would be at your own discretion and how you want to name functions, etc. It also does not need to be called initalize , that was just my name of preference.您还可以将initialize方法重构为不同的方法,但这取决于您自己的判断以及您希望如何命名函数等。它也不需要称为initalize ,这只是我的偏好名称。

thanks for answering but I'm not clear.感谢您的回答,但我不清楚。 Where do I do the initial configuration of the socket?我在哪里进行套接字的初始配置? I don't have such configuration in the controller我在controller中没有这样的配置

Move your socket.io code to its own module where you can export a method that shares the socket.io server instance:将您的 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;
   }
}

Then, initialize the socketio.js module in your main app file:然后,在您的主应用程序文件中初始化 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);

Then, anywhere you want to access the socket.io server instance, you can require("./socketio.js") and use the .getIO() method to get the socket.io instance:然后,在任何你想访问 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
};

Note: A typical socket.io usage convention on the server is to use io as the server instance and socket as an individual client connection socket instance.注意:服务器上典型的 socket.io 使用约定是使用io作为服务器实例,使用socket作为单独的客户端连接套接字实例。 Please don't try to use socket for both.请不要尝试同时使用socket This makes it clear that io.emit(...) is attempting to send to all connected clients and socket.emit() is attempting to send to a single connected client.这清楚地表明io.emit(...)正在尝试发送到所有连接的客户端,而socket.emit()正在尝试发送到单个连接的客户端。

Also note that if your route is triggered by a form post where the browser itself sends the form post, then that particular client will not receive the results of io.emit(...) done from that form post route because that browser will be in the process of loading a new web page based on the response of the form post and will be destroying its current socket.io connection.另请注意,如果您的路由是由浏览器本身发送表单帖子的表单帖子触发的,那么该特定客户端将不会收到从该表单帖子路由完成的io.emit(...)的结果,因为该浏览器将在根据表单帖子的响应加载新的 web 页面的过程中,将破坏其当前的 socket.io 连接。 If the form post is done entirely via Javascript using an Ajax call, then that webpage will stay active and will receive the results of the io.emit(...) .如果表单发布完全通过 Javascript 使用 Ajax 调用完成,则该网页将保持活动状态并接收io.emit(...)的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM