仅限登录用户,我想以某种方式通知他们,如果他们有任何例如新通知。
例如,假设某个成员向他们发送了私人消息,我想告诉用户他们有一条要查看的新消息(假设他们没有刷新页面)。
使用Nodejs和redis,我将如何做到这一点?
注意:我只需要nodejs向用户发送一个小json,说他们有新消息。
我正在考虑的工作流程如下:
1. user is logged in, a new message is sent to them.
2. somehow using nodejs and redis and long-polling, nodejs communicates back to the logged in users browser they have a pending message.
3. when nodejs sends this push notification, I then call another javascript function that will call a rest service to pull down additional json with the message.
我正在将nodejs集成到现有的应用程序中,所以我希望尽可能简单地使用nodejs来负责通知而不做任何额外的逻辑。
有人可以概述我应该如何解决这个问题吗? 我应该以某种方式使用redis http://redis.io/topics/pubsub吗? 即使在阅读了有关它的页面后,我也不确定它是如何工作的。
答案 0 :(得分:5)
如果要将node
服务集成到现有应用程序中,我宁愿使用某种消息传递系统将来自该应用程序的消息传递给node
而不是数据库,甚至是内存数据库。 为了清晰,我假设您可以使用rabbitmq。如果你确实需要使用redis,你只需要找到一种方法来使用它的发布而不是rabbitmq发布和相应的节点端订阅,但我认为整体解决方案是完全相同的。
您需要以下模块:
rabbitmq
服务器(安装复杂性与redis
相同)rabbitmq
库发送消息,支持大多数语言rabit.js
node
模块订阅消息或与外部应用程序通信
socket.io
node
模块,用于在node
服务器和客户端之间建立实时连接我还假设您的外部应用程序和node
服务器都可以访问某些共享数据库(可以是redis),其中存储了node
客户端会话信息(例如{{1} } redis-session-store
)。这将允许使用node
来验证邮件的用户,会话中的用户是否已登录以及是否需要向某些用户发送通知(由外部应用程序)。
这就是你的堆栈的样子(未抛光):
在sessionId
中定义发布商,通知您的外部应用程序需要开始/停止发送给定node
的消息。我将假设对于给定的sessionId
,可以从共享数据库中恢复用户信息(sessionId
或外部应用程序),并且可以验证用户(这里为了简单起见,检查{{1} }})。还要定义订阅者以收听用户的传入消息:
node
定义从session.authenticated_user
服务器到客户端的var context = require('rabbit.js').createContext();
var pub = context.socket('PUB');
var sub = context.socket('SUB');
连接。一旦客户的网页被(重新)加载并且socket.io
被调用,将执行以下代码(参见答案结尾处的clinet侧)。在建立新连接时,验证用户是否已登录(意味着其凭据在会话中),注册套接字处理程序并向外部应用程序发布通知以开始为此node
发送消息。此处的代码假定登录/注销时页面重新加载(因此新的io.connect()
会话)。如果不是这种情况,只需从客户端向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');
});
}
});
}
});
最后你的客户端看起来大致如此(这里是Jade,但那只是因为我已经沿着这些线路拥有整个堆栈):
rabbitmq
答案 1 :(得分:1)
以下是Flickr关于如何使用NodeJS和Redis创建高度可用且可扩展的推送通知系统的非常好的解释。
http://code.flickr.net/2012/12/12/highly-available-real-time-notifications/