node.js 在快速路由文件中使用 socket.io
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18856190/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use socket.io inside a express routes file
提问by Matthew Arkin
I'm trying to use Socket.io with Node.js and emit to a socket within the logic of a route.
我正在尝试将 Socket.io 与 Node.js 一起使用,并在路由逻辑中发送到套接字。
I have a fairly standard Express 3 setup with a server.js file that sits in the route, and then I have an index.js which sits in a routes folders that exports all the pages/publically accessible functions of the site. So they look like:
我有一个相当标准的 Express 3 设置,其中有一个位于路由中的 server.js 文件,然后我有一个 index.js,它位于路由文件夹中,该文件夹导出站点的所有页面/可公开访问的功能。所以它们看起来像:
exports.index = function (req, res) {
res.render('index', {
title: "Awesome page"
});
};
with the routing defined in server.js like:
使用 server.js 中定义的路由,例如:
app.get('/',routes.index);
I'm assuming I have to create the socket.io object in the server.js, since it needs the server object, but how can I access that object and emit to it from the index.js export functions?
我假设我必须在 server.js 中创建 socket.io 对象,因为它需要服务器对象,但是我如何访问该对象并从 index.js 导出函数发送给它?
回答by aarosil
There is a better way to do this now with Express 4.0.
现在使用 Express 4.0 有一种更好的方法可以做到这一点。
You can use app.set()to store a reference to the ioobject.
您可以使用app.set()来存储对io对象的引用。
Base configuration:
基础配置:
var app = require('express')();
var server = app.listen(process.env.PORT || 3000);
var io = require('socket.io')(server);
// next line is the money
app.set('socketio', io);
Inside route or middleware:
内部路由或中间件:
exports.foo = function(req,res){
// now use socket.io in your routes file
var io = req.app.get('socketio');
io.emit('hi!');
}
Information about app.set()and app.get()is below:
关于app.set()和的信息app.get()如下:
app.set(name, value)
Assigns setting name to value. You may store any value that you want, but certain names can be used to configure the behavior of the server. These special names are listed in the app settings table.
Calling
app.set('foo', true)for a Boolean property is the same as callingapp.enable('foo'). Similarly, callingapp.set('foo', false)for a Boolean property is the same as callingapp.disable('foo').Retrieve the value of a setting with
app.get().
app.set(名称,值)
将设置名称分配给值。您可以存储您想要的任何值,但某些名称可用于配置服务器的行为。这些特殊名称列在应用程序设置表中。
调用
app.set('foo', true)Boolean 属性与调用app.enable('foo'). 同样,调用app.set('foo', false)Boolean 属性与调用app.disable('foo').使用 检索设置的值
app.get()。
回答by hexacyanide
You can set up your routes file as a function, and pass the Socket.IO object when requiring the file.
您可以将路由文件设置为函数,并在需要该文件时传递 Socket.IO 对象。
module.exports = function(io) {
var routes = {};
routes.index = function (req, res) {
io.sockets.emit('payload');
res.render('index', {
title: "Awesome page"
});
};
return routes;
};
Then require routes like this:
然后需要这样的路线:
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
var routes = require('./routes')(io);
回答by johnjohn
aarosil's answer was great, but I ran into the same problem as Victor with managing client connections using this approach. For every reload on the client, you'd get as many duplicate messages on the server (2nd reload = 2 duplicates, 3rd = 3 duplicates, etc).
aarosil 的回答很好,但我遇到了与 Victor 相同的问题,使用这种方法管理客户端连接。对于客户端上的每次重新加载,您会在服务器上收到尽可能多的重复消息(第二次重新加载 = 2 次重复,第三次 = 3 次重复等)。
Expanding on aarosil's answer, I used this approach to use the socket object in my routes file, and manage the connections/control duplicate messages:
扩展 aarosil 的答案,我使用这种方法在我的路由文件中使用套接字对象,并管理连接/控制重复消息:
Inside Server File
内部服务器文件
// same as aarosil (LIFESAVER)
const app = require('express')();
const server = app.listen(process.env.PORT || 3000);
const io = require('socket.io')(server);
// next line is the money
app.set('socketio', io);
Inside routes file
内部路由文件
exports.foo = (req,res) => {
let socket_id = [];
const io = req.app.get('socketio');
io.on('connection', socket => {
socket_id.push(socket.id);
if (socket_id[0] === socket.id) {
// remove the connection listener for any subsequent
// connections with the same ID
io.removeAllListeners('connection');
}
socket.on('hello message', msg => {
console.log('just got: ', msg);
socket.emit('chat message', 'hi from server');
})
});
}
回答by Emad Said
Whats wrong with just using
只是使用有什么问题
global.io = require('socket.io').listen(server);
回答by jme11
Super late addition here, but I wanted to access a socket in my routes and specifically wanted to broadcast a message after saving to the database. I used the answer provided by @aarosil to set/get the io object, sent the each client its socket id on connection, then used the socket id in the route to be able to use socket.broadcast.emit()instead of io.emit().
在这里添加超级晚,但我想访问我的路由中的套接字,并且特别想在保存到数据库后广播一条消息。我使用@aarosil 提供的答案来设置/获取 io 对象,在连接时向每个客户端发送其套接字 id,然后在路由中使用套接字 id 来socket.broadcast.emit()代替io.emit().
In server:
在服务器中:
const io = require('socket.io')(server)
app.set('socketio', io)
io.on('connect', socket => {
socket.emit('id', socket.id) // send each client their socket id
})
I send the socket id with each req and then I can do the following in my routes:
我发送每个请求的套接字 ID,然后我可以在我的路由中执行以下操作:
router.post('/messages', requireToken, (req, res, next) => {
// grab the id from the request
const socketId = req.body.message.socketId
// get the io object ref
const io = req.app.get('socketio')
// create a ref to the client socket
const senderSocket = io.sockets.connected[socketId]
Message.create(req.body.message)
.then(message => {
// in case the client was disconnected after the request was sent
// and there's no longer a socket with that id
if (senderSocket) {
// use broadcast.emit to message everyone except the original
// sender of the request !!!
senderSocket.broadcast.emit('message broadcast', { message })
}
res.status(201).json({ message: message.toObject() })
})
.catch(next)
})
回答by Paul Duncan
module.parent.exports.serverwould also work if you exported server in the parent module.
module.parent.exports.server如果您在父模块中导出服务器,也可以使用。

