如果您正在将node
服务集成到现有应用程序中,我宁愿使用某种消息传递系统将消息从该应用程序传递到node
而不是DB,即使是内存数据库。 为了清晰起见,我会假设你可以使用rabbitmq。如果您确实需要使用redis,您只需要找到一种方法来使用它的发布,而不是使用rabbitmq发布和相应的节点端订阅,但我会想象整体解决方案是相同的。
您需要以下模块:
rabbitmq
服务器在外部应用程序发送的消息
rabbitmq
库(安装大致相同的redis
复杂性),大多数语言都支持
rabit.js
模块为node
订阅消息或与外部应用程序进行通信
socket.io
模块为node
建立node
服务器和客户端之间的实时连接
我也将承担两个您的外部应用程序和node
服务器访问某些共享数据库(可以是Redis的),其中node
客户端会话信息被存储(例如, redis-session-store
for node
)。这将允许使用sessionId
来验证消息的用途,会话中的用户是否已登录,以及某些用户是否需要发送通知(通过外部应用程序)。
这是你的筹码可能会看怎么样(糙米):
在node
定义发布通知,它需要启动/停止对给定sessionId
发送消息的外部应用程序。我将假设对于给定的sessionId
,用户信息可以从共享数据库的任一侧(node
或外部应用程序)恢复,并且可以验证用户(这里为了简化,通过检查session.authenticated_user
)。还定义了用户收听传入消息的用户:
var context = require('rabbit.js').createContext();
var pub = context.socket('PUB');
var sub = context.socket('SUB');
定义从node
服务器socket.io
连接(县)客户端。一旦客户的网页被重新加载并且io.connect()
被调用,下面的代码将被执行(参见答案末尾的clinet端)。在建立新的连接时,验证用户是否已登录(意味着它的凭证在会话中),注册套接字处理程序并向外部应用程序发布通知,以便开始为此发送消息sessionId
。此处的代码假设在登录/注销时重新加载页面(因此会话为新的socket.io
)。如果不是这种情况,只需从客户端发送相应的socket.io
消息到node
,并按照与新连接完成相同的方式在下面的方法中注册处理程序(这超出了本示例的范围):
var sessionStore = undefined; // out-of-scope: define redis-session-store or any other store
var cookie = require("cookie"),
parseSignedCookie = require('connect').utils.parseSignedCookie;
// will store a map of all active sessionIds to sockets
var sockets = {};
// bind socket.io to the node http server
var io = require('socket.io').listen(httpServer);
// assumes some config object with session secrect and cookie sid
io.sockets.on("connection", function(socket) {
if (socket.handshake.headers.cookie) {
var cks = cookie.parse(socket.handshake.headers.cookie);
var sessionId = parseSignedCookie(cks[config.connectSid], config.sessionSecret);
// retrieve session from session store for sessionId
sessionStore.get(sessionId, function(err, session) {
// check if user of this session is logged in,
// define your elaborate method here
if (!err && session.authenticated_user) {
// define cleanup first for the case when user leaves the page
socket.on("disconnect", function() {
delete sockets[sessionId];
// notify external app that it should STOP publishing
pub.connect('user_exchange', function() {
pub.write(JSON.stringify({sessionId: sessionId, action: 'stop', reason: 'user disconnected'}), 'utf8');
});
});
// store client-specific socket for emits to the client
sockets[sessionId] = socket;
// notify external app that it should START publishing
pub.connect('user_exchange', function() {
pub.write(JSON.stringify({sessionId: sessionId, action: 'start'}), 'utf8');
});
}
});
}
});
连接用户到rabbitmq
交换赶上消息,并将它们发射到客户端:
sub.connect('messages_exchange', function() {
sub.on("readable", function() {
// parse incoming message, we need at least sessionId
var data = JSON.parse(sub.read());
// get socket to emit for this sessionId
var socket = sockets[data.sessionId];
if (socket) {
socket.emit("message", data.message);
} else {
// notify external app that it should STOP publishing
pub.connect('user_exchange', function() {
pub.write(JSON.stringify({sessionId: sessionId, action: 'stop', reason: 'user disconnected'}), 'utf8');
});
// further error handling if no socket found
}
});
});
最后你的客户会看起来大致是这样的(这里的翡翠,但是这只是因为我已经有这整个沿着这些线堆叠):
script(src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js")
script(src="/socket.io/socket.io.js")
script(type='text/javascript').
$(function(){
var iosocket = io.connect();
iosocket.on('connect', function() {
// do whatever you like on connect (re-loading the page)
iosocket.on('message', function(message) {
// this is where your client finally gets the message
// do whatever you like with your new message
});
});
// if you want to communicate back to node, e.g. that user was logged in,
// do it roughly like this
$('#btnSend').click(function(event) {
iosocket.send('a message back to the node server if you need one');
});
});