Bee*_*man 3 session-variables node.js express
以下代码处理对我的应用程序登录页面的发布请求。
如果登录凭据正确,它会将is_logged_in会话变量设置true为以及user_id从数据库获取的用户 ID。
在获取凭据的查询中,如果一切顺利,我还有第二个查询来获取学生 ID。由于一些奇怪的原因,当我尝试设置req.session.student_id变量并记录我没有看到的会话对象时,它只设置了从第二个查询函数外部设置的is_logged_in和user_id变量。
router.post('/login', (req, res) => {
con.query("SELECT id, username, password FROM authorizedusers;",
(err, result) => {
if(err) throw err;
for(var i = 0; i < result.length; i++) {
if(req.body.username === result[i].username
&& req.body.password === result[i].password){
con.query(`SELECT id FROM students WHERE user_id =
${result[i].id};`, (err, result) => {
if(err) throw err;
req.session.student_id = result[0].id;
});
req.session.is_logged_in = true;
req.session.user_id = result[i].id;
return res.redirect('/');
}
}
return res.render('login', {
msg: "Error! Invalid Credentials!"
});
});
});
Run Code Online (Sandbox Code Playgroud)
这就是我记录会话对象时得到的结果。
Session {
cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true },
is_logged_in: true,
user_id: 3
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试将 设置student_id在与其他范围相同的范围内,如下所示:
router.post('/login', (req, res) => {
con.query("SELECT id, username, password FROM authorizedusers;",
(err, result) => {
if(err) throw err;
for(var i = 0; i < result.length; i++) {
if(req.body.username === result[i].username
&& req.body.password === result[i].password){
con.query(`SELECT id FROM students WHERE user_id =
${result[i].id};`, (err, result) => {
if(err) throw err;
});
req.session.student_id = "test";
req.session.is_logged_in = true;
req.session.user_id = result[i].id;
return res.redirect('/');
}
}
return res.render('login', {
msg: "Error! Invalid Credentials!"
});
});
});
Run Code Online (Sandbox Code Playgroud)
它确实有效,这就是我记录会话对象后得到的结果。
Session {
cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true },
student_id: 'test',
is_logged_in: true,
user_id: 3
}
Run Code Online (Sandbox Code Playgroud)
为什么会发生这种情况,我该如何解决?
更新
jfriend00回答了我的问题,并说我可以通过使用 mysql2 模块而不是 mysql 模块来解决我的问题。
不过,我想使用 mysql 模块。所以如果有人可以回答如何在使用 mysql 模块时解决这个问题,我会很高兴。
这是因为con.query()函数调用的非阻塞、异步特性。它启动异步操作,然后执行其后的代码行。然后,稍后的某个时候,它调用它的回调。所以,在你的这段代码中,我添加了日志:
router.post('/login', (req, res) => {
con.query("SELECT id, username, password FROM authorizedusers;", (err, result) => {
if(err) throw err;
for(var i = 0; i < result.length; i++) {
if(req.body.username === result[i].username && req.body.password === result[i].password){
con.query(`SELECT id FROM students WHERE user_id = ${result[i].id};`, (err, result) => {
if(err) throw err;
console.log("got student_id");
req.session.student_id = result[0].id;
});
req.session.is_logged_in = true;
req.session.user_id = result[i].id;
console.log("redirecting and finishing request");
return res.redirect('/');
}
}
return res.render('login', {
msg: "Error! Invalid Credentials!"
});
});
});
Run Code Online (Sandbox Code Playgroud)
你会得到这个日志:
redirecting and finishing request
got student_id
Run Code Online (Sandbox Code Playgroud)
因此,您在获取之前完成了请求student_id并将其设置到会话中。因此,当您立即尝试使用会话中的数据时,它还不存在。
如果没有承诺,这不是一个特别容易解决的问题,因为您在for循环中有一个老式的异步调用。如果您为 SQL 库使用 promise 接口,这会容易得多,因为这样您就可以对事物进行排序并且await一次只能运行一个查询 - 您当前的循环正在运行来自for并行这是行不通的以便轻松选择一个获胜者并停止其他一切。
如果您切换到mysql2然后使用 promise 版本:
const mysql = require('mysql2/promise');
Run Code Online (Sandbox Code Playgroud)
然后,你可以做这样的事情(我不是 mysql2 的专家,但希望你能看到如何使用 promise 接口来解决你的问题的想法):
router.post('/login', async (req, res) => {
try {
const [rows, fields] = await con.query("SELECT id, username, password FROM authorizedusers;");
for (let i = 0; i < rows.length; i++) {
if (req.body.username === rows[i].username && req.body.password === rows[i].password) {
let [students, fields] = await con.query(`SELECT id FROM students WHERE user_id = ${rows[i].id};`);
req.session.student_id = students[0].id;
req.session.is_logged_in = true;
req.session.user_id = rows[i].id;
return res.redirect('/');
}
}
return res.render('login', { msg: "Error! Invalid Credentials!" });
} catch (e) {
console.log(e);
res.sendStatus(500);
}
});
Run Code Online (Sandbox Code Playgroud)
您现有的实现也有其他缺陷,可以使用以下代码进行更正:
var在异步回调函数中永远不会正确。if (err) throw err错误处理不足。您需要捕获错误,记录它并在响应处理程序中收到错误时发送错误响应。res.render()在循环中的任何数据库调用完成之前调用。| 归档时间: |
|
| 查看次数: |
124 次 |
| 最近记录: |