使用express在node.js中编写登录

ari*_*rio 2 javascript node.js express

我正在使用express框架在node.js中为一个网站编写一个登录名.但是,代码以奇怪的顺序执行,我不知道如何解决它.这是相关代码的简化版本:

app.post('/login', function(req, res){
    var login_error;
    if (!req.session.username) { //if no one is logged in
        if (req.body.user != undefined && req.body.pass != undefined) {
            client.query('USE data', function(error, results) {}
        });
        client.query('SELECT id FROM user WHERE username=? AND password=?',[reg.body.user, req.body.pass],
        function(err, results,fields) {
            if (err || results.length == 0) {
                login_error=1;
                console.log('a '+login_error); //LINE A
            }
        });
    }
    console.log('b '+login_error);  //LINE B
    if (login_error == undefined) {
        req.session.username=req.body.user;
    }
    client.end();
}
res.render('login', {
    user: req.session.username,
    login_error: login_error
});
Run Code Online (Sandbox Code Playgroud)

即使用户名/传递组合不在数据库中,该页面也始终使用login_error = undefined进行渲染.在这种情况下,LINE A打印login_error = 1,但LINE B打印login_error = undefined.此外,LINE B在LINE A之前打印,即使它稍后出现.我不太确定这里发生了什么.

How*_*ard 6

这种情况正在发生,因为回调的工作方式.在这段代码中:

    client.query('SELECT id FROM user WHERE username=? AND password=?',[reg.body.user, req.body.pass],
    function(err, results,fields) {
        if (err || results.length == 0) {
            login_error=1;
            console.log('a '+login_error); //LINE A
        }
    });
Run Code Online (Sandbox Code Playgroud)

包含A行的函数不会立即执行.相反,client.query立即返回并继续执行,直到B行.

然后当select查询返回时,执行回调函数.因此,按照执行的顺序,它可能会 B行之后,即使它预先出现在源代码中.

考虑这个例子

client.query('SELECT 1 AS Res', function(err, results) {
  console.log(results.fields.Res);
});

client.query('SELECT 2 AS Res', function(err, results) {
  console.log(results.fields.Res);
});
Run Code Online (Sandbox Code Playgroud)

您可能会发现这会产生以下输出:

2
1
Run Code Online (Sandbox Code Playgroud)

因为第二个查询可能比第一个查询返回得更快.

这是Node的强大之源 - 代码不会阻塞,它是异步的,所以速度很快.

为了使您的示例按预期工作,您应该重构它以在单独的函数中调用需要知道查询结果的代码.例如更像这样的东西:

function processLogin(login_error) {
  console.log('b '+login_error);  //LINE B
  if (login_error !== true) {
    req.session.username=req.body.user;
  }

  res.render('login', {
      user: req.session.username,
      login_error: login_error
  });
}

app.post('/login', function(req, res){
    if (!req.session.username) { //if no one is logged in
        if (req.body.user != undefined && req.body.pass != undefined) {
            client.query('USE data', function(error, results) {}
        });
        client.query('SELECT id FROM user WHERE username=? AND password=?',[reg.body.user, req.body.pass], function(err, results,fields) {
            if (err || results.length == 0) {
                process_login(true);
            } else {
                process_login(false);
            }
        });
    }
    client.end();
}
Run Code Online (Sandbox Code Playgroud)

这段代码不会马上工作,但请注意我是如何将res.render调用移动到一个函数中的,我正在调用client.query的回调函数.现在,您需要允许该回调访问res变量,方法是将其设置为全局(如果您在专用的"登录"模块中,这是好的,但在其他方面是个坏主意),或者将其传递给作为一个参数,这可能是更好的.

仅仅因为一行代码出现在另一行之后,并不一定意味着它会在它之后执行,如果涉及回调的话.你可能熟悉的类似行为的东西是超时; 考虑一下:

setTimeout(function() {
  console.log(1);
}, 1000);
console.log(2);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您应该会看到以下内容:

2
1
Run Code Online (Sandbox Code Playgroud)

与mysql查询之类的回调完全相同.而不是整个进程等待client.query返回,执行继续,您将依赖于client.query结果的所有内容放入您发送给client.query的回调中.