我正在研究'更改密碼'功能。我開始瞭解更多關於承諾,並有以下代碼:如何避免Promise鏈中'已發送頭'?
router.post('/change-password', verifyToken, csrfProtection, (req, res, next) => {
if (!req.body.password_current || !req.body.password_new) {
req.flash('info', 'Please fill in both fields.');
return res.redirect('/change-password');
}
const data = {};
data.password = req.body.password_new;
tokenHandler.verifyToken(req.cookies.token)
.then((decoded) => {
return User.findOne({ '_id.user_id': decoded.user });
})
.then((user) => {
data.userId = ObjectId(user._id.user_id);
return bcrypt.compare(req.body.password_current, user.password);
})
.then((allowed) => {
if (!allowed) {
return res.redirect('/change-password');
}
console.log('I am not here');
return User.findOneAndUpdate({ '_id.user_id': data.userId }, { password: data.password }, { new: true });
})
.then(() => {
return res.redirect('/change-password');
})
.catch((err) => {
return next(err);
});
});
我很喜歡承諾是如何防止'回調地獄'。問題是我收到'headers already sent'錯誤。我知道那是因爲我無法逃脫這個鏈條,並且它保存了所有的結果(除非你拋出一個錯誤)。爲了解決這個問題,我使用了以下內容:
router.post('/change-password', verifyToken, csrfProtection, (req, res, next) => {
if (!req.body.password_current || !req.body.password_new) {
req.flash('info', 'Please fill in both fields.');
return res.redirect('/change-password');
}
const data = {};
data.password = req.body.password_new;
tokenHandler.verifyToken(req.cookies.token)
.then((decoded) => {
User.findOne({ '_id.user_id': decoded.user }).then((user) => {
data.userId = ObjectId(user._id.user_id);
bcrypt.compare(req.body.password_current, user.password).then((allowed) => {
if (!allowed) {
return res.redirect('/change-password');
}
User.findOneAndUpdate({ '_id.user_id': data.userId }, { password: data.password }).then((doc) => {
console.log(doc);
return res.redirect('/change-password');
});
});
});
});
});
問題是:是否有更好的解決方案來修復'header already sent'錯誤。因爲我覺得我的解決方案實際上離「回撥地獄」結構只有幾步之遙。
您只需要嵌套'then'鏈中應該進入條件的'else'部分的部分,而不是所有部分。你也不應該在最後刪除'.catch()'。 – Bergi
你真的想要'res.redirect'('/ change-password');'即使它們不被'允許'嗎?在這種情況下,不要調用'res.redirect'兩次,而是將'User.findOneAndUpdate(...)'返回到'if(允許)'內並繼續鏈接到重定向調用。 – Bergi
謝謝你的回答,並提醒我忘了'.catch()'塊。 :-)我需要重定向來傳遞不同的'flash'消息。我本可以找到其他解決方案來防止'header already sent'錯誤。但我真的很好奇,如何用這種結構來阻止它。現在我明白了! – Jeffrey