Nodejs作用域问题
问题发现
我的一个node项目启动时有个接口的访问报错,报错如下ReferenceError: param is not defined
,看了一下代码如下:
router.get('/ismytask', function(req, res){
var param = url.parse(req.url, true).query;
userBiz.isMyTask(param, function(err, rows, fields){
msg.defaultMsgFun(err, rows, fields, res, raphLog);
});
});
userBiz.isMyTask = function(params, cb){
var iTableNum = params.iQQ % iUserTableCnt;
var szWhere = " and ( 1 = 2 or ";
if(typeof param.iTaskID == 'string'){
var taskArray = params.iTaskID.split('|');
for(var i in taskArray){
szWhere = szWhere + " iTaskID = " + taskArray[i];
if(i == (taskArray.length - 1)){
break;
}
szWhere = szWhere + " or ";
}
}
else{
szWhere = szWhere + " iTaskID = " + params.iTaskID;
}
szWhere = szWhere + ")";
var insertParams = [iTableNum, params.iQQ, szWhere];
sqlPool.excute(160, insertParams, cb);
};
可以看到在userBiz.isMyTask
函数中param确实没定义,因此抛错,奇怪的是这段代码在线上运行一直是正常的,用nodejs一段时间了,发现由于js的健壮性,会产生很多隐形的坑,一般情况下都很难发现,给有些问题的排查带来了隐形成本,还不如更加严格的语言容易排查问题,这里决定解决一下这个问题,面得以后给自己留坑。
问题分析
首先想到的是js的函数嵌套定义的作用域问题,对于这样的代码:
function g(){
var a = "hello kitty!";
function f(){
console.log(a);
}
f();
}
g();
函数f()是可以访问到a变量的,输出结果为hello kitty!,但是我上面的代码,两个函数并不是嵌套定义的,因此userBiz.isMyTask函数应该是访问不到router.get中的变量param的,那么猜测应该是有定义param的全局变量,通过看代码,果然发现有param的全局变量定义:
function check_result(bCheck, iErr, req, res, next){
res.set("Access-Control-Allow-Origin", "*");
if(bCheck){
param = url.parse(req.url, true).query;
if(interfaceBiz.checkParam(param)){
next();
}else{
res.jsonp(msg.getMsg(msg.code.ERR_VALID_QUERY));
}
}else{
res.jsonp(msg.getMsg(iErr));
}
}
在执行前面那段代码之前,先运行了这段代码,js定义变量不加var修饰默认就是全局变量,因此在userBiz.isMyTask中就可以访问到param变量了。这里恰巧有个bCheck开关,线上是打开的,我自己的环境是关闭的,因此我的环境报错了,线上环境却运行正常。。
总结
两个Bug居然负负得正让程序正常运行,JS比较容易写出这种不可掌控的代码,怒修Bug之余也想了想,感觉还是C,C++写的后台比较可控。