node.js - “未定义”以某种方式破坏了承诺树
问题描述
我正在运行一个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'中的代码中。
这对我来说完全没有意义。似乎来自检查数据库中现有用户电子邮件的“未定义”响应阻止了代码其余部分的执行,并且莫名其妙地引发了数据库写入的“拒绝”。
这是要了我的命。我花了大约一周的时间,我似乎离解决这个问题还差得远。如果我处理来自“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...
我要感谢那些回复这篇文章的人。我非常感谢他们的时间和建议,使我能够达到现在显然是功能性代码的这一点。此外,这些回复很有启发性,我从收到的帮助中学到了一些新技术。
解决方案
我认为问题是return Promise.reject("Email EXTANT");
。如果你想中断执行,你可以return res
改用。
使用 async/await 方法尝试下面的示例。
编辑:添加 checkEmail 更新
//server.js
const db = require("./routes/queries");
const traffic = require("./routes/traffic");
app.post("/_register", async function (req, res) {
if (!req.body) {
console.log("ERROR: req.body has NOT been returned...");
return res.sendStatus(400);
}
var newToken = shortid.generate();
var client = req.body.user_email;
var creds = req.body.user_password;
var firstname = req.body.user_name;
try {
const direction = await db.sanitation(client, creds, firstname);
const foundusers = await db.checkEmail(client);
if (foundusers.length) {
console.log(
"HEY THERE IS ALREADY A USER WITH THAT EMAIL!",
foundusers[0]
);
if (foundusers[0].status === "active") {
console.log("Email EXTANT");
return res.redirect("/client_login");
}
}
console.log(
"USER EMAIL NOT CURRENTLY IN DATABASE...THEREFORE IT IS OK...UNDEFINED!!!"
);
const hashedPassword = await traffic.hashPassword(creds);
console.log("PASSWORD HASHED");
const hashedName = await traffic.hashUsername(firstname);
await db.createUser(hashedName, client, hashedPassword, newToken);
console.log("REGISTERED A NEW CLIENT JOIN...!!!");
return res.redirect("/landing");
} catch (err) {
console.log("THERE WAS AN ERROR IN THE SEQUENTIAL PROCESSING..." + err);
return res.redirect("/");
}
});
我更新了 checkEmail 功能。
提醒:您应该创建一个 db.js 来导出池,而不是在 checkEmail.js 文件中创建一个池。然后当您需要在其他函数中查询时,他们可以从中导入池,而不是重新创建新池。
const Pool = require("pg").Pool;
const pool = new Pool({
user: "postgres",
host: "127.0.0.1",
database: "myDB",
password: "password",
});
export const checkEmail = async function (mail) {
try {
const res = await pool.query("SELECT * FROM clients WHERE email = $1", [
mail,
]);
console.log(res);
return res.rows;
} catch (err) {
throw err;
}
};
推荐阅读
- iis - IIS - 发布 - 错误 405 方法不允许
- node.js - 在 Jenkins 管道中合并多个笑话覆盖率报告
- python - 403 客户端错误:禁止访问 url:https://api.twitter.com/oauth/request_token - 无法使用 Twitter 登录
- c++ - 如何将对象函数的实例传递给另一个函数?
- batch-file - 有没有办法编写批处理文件以使用设置变量重命名文件?
- swift - 选择可重复使用的表格视图单元格时索引超出范围
- c# - 实体框架数据库优先方法 - 如何制作异步方法?
- sql - 如何删除sqlite中的第n行表?
- c++ - 为什么我对“鱼”挑战的 C++ 解决方案失败了?
- java - 在哪里增加堆大小 - jboss 或 java?