Запись логина в node.js с использованием экспресс - PullRequest
2 голосов
/ 30 января 2012

Я пишу логин для сайта в 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, даже если она появляется позже Я не совсем уверен, что здесь происходит.

1 Ответ

6 голосов
/ 30 января 2012

Это происходит из-за того, как работают обратные вызовы. В этом коде:

    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.

Затем, когда возвращается запрос выбора, выполняется функция обратного вызова. Таким образом, в порядке выполнения, он, вероятно, придет после строки 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, либо сделав его глобальным (что хорошо, если вы находитесь внутри выделенного модуля 'login', но в противном случае это плохая идея), либо передав его в функция в качестве аргумента, который может быть предпочтительным.

То, что строка кода появляется после другой, не обязательно означает, что она будет выполнена после нее, если задействован обратный вызов. То, что действует аналогично, с которым вы, возможно, знакомы, это тайм-ауты; Учтите это:

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

В этом случае должно быть очевидно, что вы увидите следующее:

2
1

Точно так же с обратными вызовами к таким вещам, как запросы MySQL. Вместо всего процесса, ожидающего возврата client.query, выполнение продолжается, и вы помещаете все, что зависит от результатов client.query, в обратный вызов, который вы отправляете в client.query.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...