【发布时间】:2014-03-13 02:57:44
【问题描述】:
我有一个在 Rails 和 Backbone.js 上运行的单页应用程序。我通过 Redis 使用 Node.js 将数据推送和同步到客户端。我正在尝试理解、保护和优化套接字通信。
使用 console.log 编写时,我看到一些日志行 (console.log('Redis connection on ..')) 变得重复(见下文)。
谁能解释我为什么?通过我的代码实现,是否有一些我不理解的特定 Node.js 行为?
这是我的 Node.js 代码:
var io = require('socket.io').listen(3003);
var redis = require('redis');
var cookie = require("cookie");
var redis_subs = redis.createClient(6379, "localhost");
var redis_auth = redis.createClient(6379, "localhost");
var authenticated = false;
var authentication_status = function (status) {
if (status === true) {
console.log('Authentication status is true.');
}
else {
console.log('Authentication status is false.');
}
authenticated = status;
};
redis_subs.subscribe('application_channel');
io.configure(function () {
io.set('authorization', function (data, callback) {
console.log('Cross authentication...');
if (data.headers.cookie) {
data.cookie = cookie.parse(data.headers.cookie);
data.sessionID = data.cookie['_validation_token_key'];
redis_auth.hget(["sessionStore", data.sessionID], function (err, session) {
if (err || !session) {
console.log('Socket.io authorization say false');
return callback(authentication_status(false), false);
}
else {
data.session = JSON.parse(session);
console.log('Socket.io authorization say true');
return callback(authentication_status(true), true);
}
});
}
else {
console.log('Socket.io authorization say false');
return callback(authentication_status(false), false);
}
});
});
io.on('connection', function(socket){
if (socket.handshake.session) {
var user_socket_channel = socket.handshake.session['user_socket_channel']
redis_subs.on('message', function(redis_channel, rawdata) {
console.log('Redis connection on '+redis_channel);
console.log('Handshaked Session, authenticated user. All channels allowed.');
var data = JSON.parse(rawdata);
if (data.channel) { var socket_channel = data.channel; }
else { var socket_channel = user_socket_channel; }
var rails_data = data.data;
console.log('Socket.io emiting on ['+socket_channel+']')
socket.emit(socket_channel, rails_data);
});
}
else {
redis_subs.on('message', function(redis_channel, rawdata) {
console.log('Redis connection on '+redis_channel);
console.log('No handshaked Session, unauthenticated user. Public channels allowed.');
var data = JSON.parse(rawdata);
var rails_data = data.data;
console.log('Socket.io emiting on [public]')
socket.emit('public', rails_data);
});
}
});
这是我测试它的方式,以及日志重复的具体用例:
在登录时加载页面,使用网络浏览器1(例如:Firefox);输出:
info - socket.io started
Cross authentication...
Socket.io authorization say true
Authentication status is true.
debug - authorized
info - handshake authorized bJxm_IcWl2mKZT4Ed-kV
debug - setting request GET /socket.io/1/websocket/bJxm_IcWl2mKZT4Ed-kV
debug - set heartbeat interval for client bJxm_IcWl2mKZT4Ed-kV
debug - client authorized for
debug - websocket writing 1::
加载与浏览器2(例如:Chrome)注销的同一页面
Cross authentication...
Socket.io authorization say false
Authentication status is false.
debug - authorized
info - handshake unauthorized
通过page/browser1 (Firefox) -> Rails -> Redis 发送一些数据,输出:
Redis connection on application_channel
Handshaked Session, authenticated user. All channels allowed.
Socket.io emiting on [hLTYXuvP+13aQlIT9CZiYc1i9eg=]
debug - websocket writing 5:::{"name":"hLTYXuvP+13aQlIT9CZiYc1i9eg=","args":[null]}
在 browser2 上重新加载页面(Chrome,已注销),仍然输出
Cross authentication...
Socket.io authorization say false
Authentication status is false.
debug - authorized
info - handshake unauthorized
在 browser1/Firefox 上重新加载页面,并通过页面和 Rails 向 Redis 推送更多数据,输出:
Redis connection on application_channel
Handshaked Session, authenticated user. All channels allowed.
Socket.io emiting on [hLTYXuvP+13aQlIT9CZiYc1i9eg=]
Redis connection on application_channel
Handshaked Session, authenticated user. All channels allowed.
Socket.io emiting on [hLTYXuvP+13aQlIT9CZiYc1i9eg=]
debug - websocket writing 5:::{"name":"hLTYXuvP+13aQlIT9CZiYc1i9eg=","args":[null]}
如您所见,事件被复制了,Redis 监听器现在捕获了两个连接; 每次我重新加载 page1/Firefox 时,它都会再复制一次(3,4,5...)。
我不明白这种行为。我错过了什么?
顺便说一句,正如您所看到的,我并不真正了解 Socket.io configure、set authorization 和 callback 的目标,返回 true 或 false,因为 Node 正在到达 io.on('connection') 和 Redis 侦听器无论如何。
【问题讨论】:
-
我看到你在 redis_subs 客户端上有两个订阅。一种用于未经身份验证的用户,另一种用于经过身份验证的用户。在您的 Firefox 日志中,我看到您首先以未经身份验证的用户身份进入,然后您可能进行了此订阅,然后您进行了身份验证并进行了另一个订阅。所以你现在有两个听众。但这有点猜测,没有终端来检查这一点。