在控制器中使用 socket.io
Posted
技术标签:
【中文标题】在控制器中使用 socket.io【英文标题】:Use socket.io in controllers 【发布时间】:2013-11-02 18:13:16 【问题描述】:如果将新对象插入数据库,我只需要socket.io
到emit
到clients
的消息。所以我的想法是直接从控制器的insert-method
发出消息。在我的server.js
文件中,我正在创建socket.io object
并尝试使其可供其他模块访问:
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
//make socket io accessible for other modules
module.exports.io = io;
在我的控制器中,我尝试过以这种方式使用 socket.io:
var io = require('../server').io;
...
io.sockets.on("connection", function(socket)
passportSocketIo.filterSocketsByUser(io, function (user)
return user.workingAt === socket.handshake.user.workingAt;
).forEach(function(s)
s.send("news", insertedObject);
);
);
我在这里卡住了。 "connection" 事件永远不会被触发,因此不会发出消息。这是在separate
文件中使用socket.io
的正确方法吗?不幸的是,我找不到复杂的socket.io
示例。
【问题讨论】:
你不能打电话给io.sockets.emit()
吗?
我不想将消息发送给所有用户。因此我需要套接字对象来过滤活动套接字......我更新了我的代码
我很想调试应用程序,并逐步了解在创建和过滤套接字时会发生什么,或者添加一些日志记录以实现相同的效果。你对事物运作方式的假设之一将是任性的。我假设您想在 HTTP 请求发生时将消息发送到特定的套接字?我认为你的方法应该可行,但我个人会将所有 socket.io 访问拉到一个包装模块中,并导出我需要的内容,例如mysockets.start(port)
和 mysockets.sendNews(user,msg)
目前我将所有 socket.io 的东西包装在一个单独的模块中。我回来报告
我混合使用了 socket.io 和 Node.js Events。检查this anwser。
【参考方案1】:
您正在尝试反转控制流程。这样做的方法是让您的控制器实现一个接口(API),您的服务器可以使用该接口将控制权传递给。
一个简单的例子是:
在mycontroller.js
// no require needed here, at least, I don't think so
// Controller agrees to implement the function called "respond"
module.exports.respond = function(socket_io)
// this function expects a socket_io connection as argument
// now we can do whatever we want:
socket_io.on('news',function(newsreel)
// as is proper, protocol logic like
// this belongs in a controller:
socket.broadcast.emit(newsreel);
);
现在在server.js
:
var io = require('socket.io').listen(80);
var controller = require('./mycontroller');
io.sockets.on('connection', controller.respond );
这个例子很简单,因为控制器 API 看起来很像 socket.io 回调。但是如果你想将其他参数传递给控制器呢?像io
对象本身或代表端点的变量?为此,您需要做更多的工作,但这并不多。这与我们经常用来打破或创建闭包的技巧基本相同:函数生成器:
在mycontroller.js
module.exports.respond = function(endpoint,socket)
// this function now expects an endpoint as argument
socket.on('news',function(newsreel)
// as is proper, protocol logic like
// this belongs in a controller:
endpoint.emit(newsreel); // broadcast news to everyone subscribing
// to our endpoint/namespace
);
现在在服务器上,我们需要做更多的工作才能通过终点:
var io = require('socket.io').listen(80);
var controller = require('./mycontroller');
var chat = io
.of('/chat')
.on('connection', function (socket)
controller.respond(chat,socket);
);
请注意,我们直接传递了socket
,但我们通过闭包捕获了chat
。有了这个,您可以拥有多个端点,每个端点都有自己的控制器:
var io = require('socket.io').listen(80);
var news_controller = require('./controllers/news');
var chat_controller = require('./controllers/chat');
var news = io
.of('/news')
.on('connection', function (socket)
news_controller.respond(news,socket);
);
var chat = io
.of('/chat')
.on('connection', function (socket)
chat_controller.respond(chat,socket);
);
实际上,您甚至可以为每个端点使用多个控制器。请记住,控制器除了订阅事件之外什么都不做。正在监听的是服务器:
var io = require('socket.io').listen(80);
var news_controller = require('./controllers/news');
var chat_controller = require('./controllers/chat');
var chat = io
.of('/chat')
.on('connection', function (socket)
news_controller.respond(chat,socket);
chat_controller.respond(chat,socket);
);
它甚至适用于普通的 socket.io(无端点/命名空间):
var io = require('socket.io').listen(80);
var news_controller = require('./controllers/news');
var chat_controller = require('./controllers/chat');
io.sockets.on('connection', function (socket)
news_controller.respond(socket);
chat_controller.respond(socket);
);
【讨论】:
感谢您的精彩回答,看起来非常直截了当。但是我有一个问题:如果我想在多个控制器中使用 socket.io 怎么办? 这在第二部分中介绍 - 为每个控制器使用单独的端点。 谢谢,很好的回答 在我的回答中添加了更多示例。 你需要一个不同的控制器来处理 socket.io,因为它是一个不同的服务。但是为了确保发射,你可以以同样的方式传递 socket.io。让您的控制器接受req,res,io
作为参数,然后在 app.post 中将第二个参数设为 function(req,res)TestCtrl.insert(req,res,io)
【参考方案2】:
你可以很容易地做到这一点,你只需要在 app.js 中编写套接字连接,然后你就可以在任何你想要的地方使用套接字
在app.js
文件中放入如下代码
var http = require('http').createServer(app);
const io = require('socket.io')(http);
io.sockets.on("connection", function (socket)
// Everytime a client logs in, display a connected message
console.log("Server-Client Connected!");
socket.join("_room" + socket.handshake.query.room_id);
socket.on('connected', function (data)
);
);
const socketIoObject = io;
module.exports.ioObject = socketIoObject;
在任何文件或控制器中,您可以像下面这样导入该对象
const socket = require('../app'); //import socket from app.js
//you can emit or on the events as shown
socket.ioObject.sockets.in("_room" + req.body.id).emit("msg", "How are You ?");
【讨论】:
【参考方案3】:You can solve this problem declaring io instance as global variable.
at the last line of my app.js: IoInstance = require("./socket.io")(server);
at the './socket.io' :
const chatNamespace = require("./namespaces/chat");
const notificationsNamespace = require("./namespaces/notifications");
const auth = require("./middlewares/auth");
module.exports = (server) =>
const io = require("socket.io").listen(server);
io.of("/chats")
.use(auth)
.on("connect", (socket) => chatNamespace( io, socket ));
io.of("/notifications")
.use(auth)
.on("connect", (socket) => notificationsNamespace( io, socket ));
return io;
;
then, you can use the IoInstance wherever you want, event into your controller. Btw, I could have use it into my namespaces as well, but I've just realized it right now.
example of implementation in the testController.js:
module.exports = async (req, res) =>
IoInstance.of("/notifications")
.to("myUserId")
.emit("sendNotification", ["test", "test1"]);
return res.send("oioi");
;
【讨论】:
以上是关于在控制器中使用 socket.io的主要内容,如果未能解决你的问题,请参考以下文章
Node.js + AngularJS + Socket.io:推送的数据在控制器中不可用