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

标签 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
});

即使用户名/密码组合不在数据库中,页面始终呈现 login_error=undefined。在这种情况下,LINE A 正在打印 login_error=1,而 LINE B 正在打印 login_error=undefined。此外,LINE B 在 LINE A 之前打印,即使它出现得更晚。我不太确定这里发生了什么。

最佳答案

这是因为回调的工作方式。在这段代码中:

    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
        }
    });

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

Then when the select query returns, your callback function executes.因此,按照执行顺序,它可能会在 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);
});

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

2
1

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

这就是 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();
}

此代码不会立即运行,但请注意我是如何将 res.render 调用移动到一个函数中的,该函数是我从 client.query 的回调中调用的。现在,您需要允许该回调访问 res 变量,方法是将其设为全局变量(如果您在专用的“登录”模块中,这很好,但否则是个坏主意),或者将其传递给用作参数,这可能更可取。

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

setTimeout(function() {
  console.log(1);
}, 1000);
console.log(2);

在这种情况下,很明显您会看到以下内容:

2
1

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

关于javascript - 使用 express 在 node.js 中编写登录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9057075/

相关文章:

javascript - 如何在 api 调用中添加 header ?

javascript - 在 div 上叠加页脚

javascript - 无法理解为什么此验证未按预期工作

node.js - trigger.io 运行网页错误

node.js - 具有异步回调的单元测试快速路由

JavaScript:全局变量代码示例 "Use Strict"说明

javascript - 如何使用 NodeJS 上的 GraphicsMagick 提取 GIF 的第一帧并将其保存为 PNG?

node.js - 如何在 Bluemix 中向 Node 应用程序发出 cors 请求

node.js - 是否可以使用nano通过node.js在cloudant(couchdb)中动态添加 View

javascript - 当响应完成时,我应该在快速响应(流)对象中处理哪些事件?