【发布时间】:2021-11-24 14:11:45
【问题描述】:
我正在运行Node.js/Express 应用程序。在这段代码中,我有一个函数,它接受来自“表单”的数据来注册一个“新用户”。此函数获取输入的用户信息并执行一些任务,例如检查非法字符,检查确定输入的电子邮件是否已经存在于数据库中,对输入的名称和密码进行“哈希”处理,最后写入 (PostGres)数据库“新”用户信息。所有这些代码都被格式化为一个“承诺树”,因此每个任务都是按顺序完成的,一个接一个。代码如下:
//server.js
const db = require('./routes/queries');
const traffic = require('./routes/traffic');
...
app.post('/_register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var newHash, newName;
var newToken = shortid.generate();
var client = req.body.user_email;
var creds = req.body.user_password;
var firstname = req.body.user_name;
db.sanitation(client, creds, firstname).then(function (direction) {
console.log('USER-SUPPLIED DATA HAS PASSED INSPECTION');
return db.checkEmail(client); //<==call database query here to check for existing email
}).then(function (founduser) {
if (typeof foundUser != "undefined") {
console.log('HEY THERE IS ALREADY A USER WITH THAT EMAIL!', foundUser);
if (founduser.status === "active") {res.redirect('/client_login'); }
return Promise.reject("Email EXTANT"); //break out of promise chain...to prevent additional code processing below...
} else {
console.log('USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...UNDEFINED!!!'); //appears in log
return traffic.hashPassword(creds); //hash password and continue processing code below...
} //'foundUser' is 'undefined'...OR NOT...
}).then(function (hashedPassword) {
console.log('PASSWORD HASHED'); //does NOT appear in logs
newHash = hashedPassword;
return traffic.hashUsername(firstname);
}).then(function (hashedName) {
console.log('NAME HASHED'); //does NOT appear in logs
newName = hashedName;
return db.createUser(newName, client, newHash, newToken);
}).then(function (data) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
},
function(error) {
console.log('USER REGISTRATION FAILURE...'); //<==THIS MESSAGE SHOWS IN 'LOGS'...WHY???
}
).then(function () {
res.redirect('/landing'); //this page re-direction DOES occur...
}).catch(function (err) {
console.log('THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING...' + error);
res.redirect('/');
});
}); //POST 'register' is used to register NEW users...
这是我的问题。当执行此代码并且用户电子邮件尚未在数据库中时,在我的日志中我看到消息“用户电子邮件当前不在数据库中......因此它没问题......未定义!!!” ...这是意料之中的,因为电子邮件不在数据库中。从这一点开始,代码应该继续处理,首先“散列”用户密码,然后继续沿着“承诺树”向下移动。
实际上发生的情况是用户密码和名称的“散列”似乎没有发生......因为我没有看到任何日志消息表明它们已执行。相反,我在日志中看到以下消息“USER REGISTRATION FAILURE...”,这表明写入数据库的代码“失败”(拒绝)。
我的问题是为什么我从“checkEmail”函数检查“未定义”响应的部分似乎没有在其中执行我的代码(“return traffic.hashPassword(creds);”函数)然后随后抛出'return db.createUser'中的代码中的'reject'。
这对我来说完全没有意义。似乎来自检查数据库中现有用户电子邮件的“未定义”响应阻止了代码其余部分的执行,并且莫名其妙地引发了数据库写入的“拒绝”。
这可要了我的命。我花了大约一周的时间,我似乎离解决这个问题还差得远。如果我处理来自“checkEmail”调用的“未定义”返回的代码在某种程度上不正确,有人可以演示执行此操作的正确方法吗?非常感谢任何建议。
我在上面的代码中添加了注释符号来说明日志中显示的内容和未显示的内容
更新:
根据我收到的反馈,我使用两种不同的方法重新编写了上面的代码。这是第一个:
app.post('/register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var newHash, newName;
var client = req.body.client_email;
var creds = req.body.client_password;
var newToken = shortid.generate();
var firstname = req.body.client_name;
try {
const users = db.checkEmail(client);
users.then(function(result) {
console.log('FINAL RESULT ROWS ARE: ' + result.rows)
if (typeof result.rows != "undefined") {
console.log('HEY THERE IS ALREADY A USER WITH THAT EMAIL!');
if (result.status === "active") {
console.log("Email EXTANT");
return res.redirect("/client_login");
} //"active"
} else {
console.log('USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...');
return traffic.hashPassword(creds);
} //'result.rows' is 'undefined'...OR NOT...
})
.then(function(result) {
console.log('PASSWORD HASHED');
console.log(result);
newHash = result;
return traffic.hashUsername(firstname);
})
.then(function(result) {
console.log('NAME HASHED');
newName = result;
return db.createUser(newName, client, newHash, newToken);
})
.then(function(result) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
})
.then(function(result) {
res.redirect('/landing'); //route to 'landing' page...
});
} catch(err) {
// handle errors
console.log('ERROR IN TRY/CATCH IS: ' + err);
}
}); //POST 'register' is used to register NEW clients...
此代码是有效的,但它总是报告“电子邮件”不在数据库中......即使事实上它是。这是输出的日志:
FINAL RESULT ROWS ARE: undefined
USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...
PASSWORD HASHED
$2b$10$vW3.YkPyoB9MG5k9qiGreOQC05rWsEIO6i.NkYg6oFqJ8byNjp.iu
NAME HASHED
REGISTERED A NEW CLIENT JOIN...!!!
这是第二个代码块,在函数中使用了“async/await”:
app.post('/register', async function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var newHash, newName;
var client = req.body.client_email;
var creds = req.body.client_password;
var newToken = shortid.generate();
var firstname = req.body.client_name;
try {
//const direction = await db.sanitation(client, creds, firstname);
const founduser = await db.checkEmail(client);
console.log('founduser ROWS ARE: ' + founduser.rows)
if (typeof foundUser != "undefined") {
console.log("HEY THERE IS ALREADY A USER WITH THAT EMAIL!", foundUser);
if (founduser.status === "active") {
console.log("Email EXTANT");
return res.redirect("/client_login");
}
} //NOT "undefined"
console.log("USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...!!!");
} catch (err) {
console.log("THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING OF THE TRY STATEMENT..." + err);
return res.redirect("/");
}
}); //POST 'register' is used to register NEW clients...
此代码也可以正常工作,但是与第一段代码一样,它总是报告“电子邮件”不在数据库中......即使事实上它是。这是输出的日志:
USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...!!!
基于这些结果,我相信任何一个代码块都可能正常运行......并且所有执行的原因都将电子邮件报告为“未定义”(即使它已经存在于数据库中)是因为“checkEmail “ 功能。我可能写错了正确返回“异步”结果。这是代码:
const Pool = require('pg').Pool;
const pool = new Pool({
user: 'postgres',
host: '127.0.0.1',
database: 'myDB',
password: 'password',
})
const checkEmail = async function(mail) {
return new Promise(function(resolve, reject) {
pool.query('SELECT * FROM clients WHERE email = $1', [mail], function(error, results) {
if (error) {
reject(new Error('Error processing a database check for email!'));
} else {
resolve(results.rows);
}
console.log('checkEmail mail: ' + mail);
console.log('checkEmail results.rows: ' + results.rows);
}) //pool.query
}); //new promise
}
是否有人能够证实我的怀疑,即上面的“try/catch”代码块都编写正确......并且调用总是返回“undefined”的问题在于“checkEmail”函数?而且,如果是这种情况......也许建议我需要如何更正“checkEmail”功能,以便在必要时正确找到数据库中的现有电子邮件。我对“异步”函数的使用并不十分熟悉,也从未尝试在查询数据库的承诺中使用它们。提前感谢您的任何回复。
更新/解决方案:
当我第一次编写“checkEmail”承诺函数时,我认为如果在数据库中发现了匹配的电子邮件,它会“解决”……如果不是,则“拒绝”。我遇到的是该功能总是“解决”,即使电子邮件不在数据库中。因此,我发现使用“object.keys”方法有助于检查是否确实从函数返回了一些数据。使用它,我可以编写现在似乎可以正常运行的代码。这是我当前的“checkEmail”功能:
//queries.js
const checkEmail = async function(mail) {
return new Promise(function(resolve, reject) {
pool.query('SELECT * FROM clients WHERE email = $1', [mail], function(error, results) {
if (error) {
reject(new Error('Error processing a database check for email!'));
} else {
resolve(results.rows);
}
console.log('checkEmail mail: ' + mail);
console.log('checkEmail results.rows: ' + results.rows);
}) //pool.query
}); //new promise
}
module.exports = {
...
checkEmail,
...
}
还有我的承诺树:
//server.js
app.post('/register', function(req, res) {
if (!req.body) {
console.log('ERROR: req.body has NOT been returned...');
return res.sendStatus(400)
}
var client = req.body.client_email;
var creds = req.body.client_password;
var newToken = shortid.generate();
var firstname = req.body.client_name;
db.sanitation(client, creds, firstname)
.then(function (direction) {
console.log('Result direction Object.keys from SANITATION: ', Object.keys(direction).length);
console.log('USER-SUPPLIED DATA HAS PASSED INSPECTION');
return db.checkEmail(client); // <==call database query here to check for existing email for existing email
})
.then(function (founduser) {
console.log('foundUser matching email in database: ', founduser);
console.log('foundUser Object.keys matching email in database: ', Object.keys(founduser).length);
if (Object.keys(founduser).length > 0) {
console.log('EMAIL IS EXTANT IN DATABASE ALREADY!');
if (founduser.length) {console.log('foundUser LENGTH matching email in database: ', founduser.length);}
if (founduser[0].status === 'active') {
console.log('USER-SUPPLIED EMAIL EQUALS THAT OF AN ACTIVE USER');
throw new Error('active'); //break out of promise chain...to prevent additional code processing below...
} else {
console.log('USER-SUPPLIED EMAIL APPEARS IN THE DATABASE');
throw new Error('Email EXTANT'); //break out of promise chain...to prevent additional code processing below...
} //founduser[0].status
} //founduser.length EXCEEDS "0"
if (Object.keys(founduser).length === 0) {
console.log('EMAIL IS NOT PRESENT IN THE DATABASE!');
return traffic.hashPassword(creds); // hash password and continue processing code below...
} //founduser.length EQUALS "0"
})
.then(function (hashedPassword) {
console.log('PASSWORD HASHED');
return traffic.hashUsername(firstname)
.then(function (hashedName) { // nested to keep hashedPassword within scope
console.log('NAME HASHED');
return db.createUser(hashedName, client, hashedPassword, newToken)
.catch(function (error) { // nested in order to catch only an error arising from db.createUser(), (not necessary other than to log out an error message).
console.log('USER REGISTRATION FAILURE...'); // this message will appear only if db.createUser() fails
throw error; // RETHROW error in order to jump to the terminal catch (and hit the `default` case).
});
});
})
.then(function (data) {
console.log('REGISTERED A NEW CLIENT JOIN...!!!');
res.redirect('/landing'); // success
})
.catch(function (err) {
switch(err.message) {
case 'active':
res.redirect('/client_login');
break;
case 'Email EXTANT':
res.redirect('/client_login');
break;
default: // all unexpected errors
console.log('THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING... ' + err.message);
res.redirect('/');
}
});
}); //POST 'register' is used to register NEW clients...
我要感谢那些回复这篇文章的人。我非常感谢他们的时间和建议,使我能够达到现在显然是功能性代码的这一点。此外,这些回复很有启发性,而且我从收到的帮助中学到了一些新技术。
【问题讨论】:
-
你能分享
traffic路由器文件吗?那里似乎有什么东西正在破坏,将执行流程更改为拒绝。traffic.hashPassword(creds);在做什么,请加代码? -
感谢您的回复。我在上面添加了该功能。我认为这不是问题......我似乎从未遇到过该功能的任何问题,除非我严重错误。再次感谢您的意见。
-
您是否尝试将调试器添加到文件并检查流程?这似乎是弄清楚流程如何进入的最佳方法,您可以检查每个变量
-
您指的是 PostGres 调试器吗?几周前我曾尝试过,但由于某种原因无法使其正常工作。
-
不,VScode 或您正在使用的任何其他 IDE 中的节点、js 调试器。在代码中添加断点并检查超出范围的地方。
标签: node.js postgresql express promise undefined