一、错误何来
玩nodebb有些日子了。之前用的是v0.4.1版本,一直用着还不错。但有朋友反应发帖时不能使用快捷键很麻烦,所以想加一个插件nodebb-plugin-shortcuts。但是使用插件后,论坛不能启动,看了看最新提交是在7天前。猜想可能是nodebb新版本修改了一些文件,插件做了适应性修改,所以想把nodebb升级到最新的v0.4.3版本。升级过程很顺畅。之前也升过一次,但是因为有些问题,就回退了。今天顺便解决一下问题,学习学习。
现在的问题是右上角的登录状态有问题。
正常的状态:
二、错误排查和解决
用chrome开发者工具查看右上角的元素属性,得到一个比较有特点的元素id名logged-in-menu
,然后作为关键字在文件中搜索
在public目录下的文件一般都是在客户端引用的。以tpl结尾的是模板文件。多了一个.app.js.swp是因为我正在用vim编辑它。
打开app.js后发现了这个函数:
function updateOnlineStatus(uid) {
socket.emit('user.isOnline', uid, function(err, data) {
$('#logged-in-menu #user_label #user-profile-link>i').attr('class', 'fa fa-circle status ' + data.status);
});
}
猜想这个函数使用socket.io与后台通信更新了用户的登录状态。 于是在浏览器模拟了一下动作,发现data确实能获取用户的登录状态。但是这个函数只是改变了一下用户在线或不在线的提示颜色。
绿色就是在线,黑色就是离线。看来问题不是这里,再找。
nodebb的核心客户端js文件叫做nodebb.min.js。可是在项目里find,没有这个文件。于是猜想可能是动态生成的,作为关键词搜索了下
最下面的两个是服务端js文件,看名字应该是元变量的设置和路由。查看src/routes/meta.js
<!-- lang: js -->
"use strict";
...
meta = require('../meta'),
...
function sendMinifiedJS(req, res, next) {
return res.type('text/javascript').send(meta.js.cache);
}
function sendStylesheet(req, res, next) {
res.type('text/css').send(200, meta.css.cache);
}
module.exports = function(app, middleware, controllers) {
app.get('/stylesheet.css', sendStylesheet);
app.get('/nodebb.min.js', sendMinifiedJS);
...
};
确实是在src/meta.js中对静态js、css文件做了压缩并缓存到了各属性的cache变量中。
<!-- lang: js -->
...
Meta.js = {
cache: undefined,
prepared: false,
scripts: [
'vendor/jquery/js/jquery.js',
...
'src/app.js',
...
],
minFile: 'nodebb.min.js',
...
minify: function(minify) {
// Prepare js for minification/concatenation
var minifier = this.minifierProc = fork('minifier.js');
minifier.on('message', function(payload) {
if (payload.action !== 'error') {
winston.info('[meta/js] Compilation complete');
Meta.js.cache = payload.data;
minifier.kill();
} else {
winston.error('[meta/js] Could not compile client-side scripts!');
winston.error('[meta/js] ' + payload.error.message);
minifier.kill();
process.exit();
}
});
this.prepare(function() {
minifier.send({
action: minify ? 'js.minify' : 'js.concatenate',
scripts: Meta.js.scripts
});
});
},
...
};
可以看到public/src/app.js也在压缩之列。
再去看看public/src/app.js吧。发现前几行就定义了一个全局变量,里边记录了用户的基本信息,可以试试。
以下是我的app变量:
username,uid竟然都为空!肯定是有问题的。
再去nodebb官方社区登录了下试试,果然有值!
继续查看app.js。nodebb为了做到实时通信,大量使用了socket.io。
app变量的值在前端是在socket.on('event:connect')时被赋予的。
刚才我的论坛里app变量有空值可能是因为升级过程中没有停机,session管理有异常导致的。
于是跟代码到了src/socket.io/indexjs的io.sockets.on('connection')。
开始我以为db.sessionStore.get(sessionID,function...)中的sessionID不对,因为我观察redis中的sessino都是以sess:作为前缀的。但是打印此处的sessionID并没有带sess:,还自以为是地加了sess:,可是还是不行。看了connect-redis(一个专门用redis做sessionStore的项目)的源码才发现,在对redis进行get操作前,默认加了前缀sess:。
查了这么久都没什么收获,看来得换个方向了。
除了右上角的登录状态显示有异常外,论坛右侧的状态统计功能也失效了。于是乎跟了一下代码,发现以下语句报undefined。代码位于node_modules/nodebb-widget-essentials/public/templates/forumstats.tpl。
// public/templates/forumstats.tpl
ajaxify.register_events([
'user.count',
'meta.getUsageStats',
'user.getActiveUsers'
]);
这个代码属于nodebb-widget-essentials。于是去github上看了一下是否有更新。发现上面代码用以下代码替换了。
$(window).on('action:ajaxify.start', function(ev) {
socket.removeListener('user.count', updateUserCount);
socket.removeListener('meta.getUsageStats', updateUsageStats);
socket.removeListener('user.getActiveUsers', updateActiveUsers);
});
突然想到,本次升级的这些异常是否因为只对nodebb本身进行了升级,而忽略了各种依赖包和插件的升级呢?于是乎...npm update
。
重启应用...问题消失...
呵呵...竟然是因为这么简单的原因...虽然是个低级错误,但还是有必要注意一下的。顺便赞一下nodebb的松耦合设计,本身只保留了很少的骨架而把比较独立的功能都做成了各种widget、plugin,从而在具体功能的实现和个性化上及其地方便。
在升级成功之后,npm install nodebb-plugin-shortcuts
即可安装快捷键,支持了包括发帖等大量的快捷键。
来源:oschina
链接:https://my.oschina.net/u/178410/blog/267760