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++写的后台比较可控。

Loading Disqus comments...
Table of Contents