我正在使用express-validator中的mongoose和next.js构建登录/注册表单。
听说,最佳实践是在前端和后端清理数据。
我在前端进行了一些验证(即检查是否通过Regex发送电子邮件,并确保输入特定长度的密码)。
但是现在我想使用Custom validator来检查mongodb数据库中是否存在电子邮件。
.post(body('username').custom(value => {
UserModel.findOne({ 'email': value }).then(user => {
if (user) {
return Promise.reject('E-mail already in use');
}
});
}),
这是我其余的代码:
var router = require('express').Router()
var UserModel = require('../models/UserModel')
var { body } = require('express-validator');
router
.route('/registration')
.get(function(req, res) {
UserModel.find({}, (err, users) => {
if (err) res.status(500).send(err)
res.json(users)
})
})
.post(body('username').custom(value => {
UserModel.findOne({ 'email': value }).then(user => {
if (user) {
return Promise.reject('E-mail already in use');
}
});
}), async(req, res, next) => {
try {
let newUser = new UserModel(req.body)
let savedUser = await newUser.save(err => {
if (err) return res.json({ success: false, error: err })
return res.json({ success: true })
})
if (savedUser) return res.redirect('/users/registration?success=true');
return next(new Error('Failed to save user for unknown reasons'))
} catch (err) {
return next(err)
}
})
module.exports = router
这是我得到的错误:
Error: Failed to save user for unknown reasons
at router.route.get.post (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/server/users/index.js:34:25)
at process._tickCallback (internal/process/next_tick.js:68:7)
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/response.js:267:15)
at /Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/server/index.js:108:17
at Layer.handle_error (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/layer.js:71:5)
at trim_prefix (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:315:13)
at /Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:335:12)
at next (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:275:10)
at Layer.handle_error (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/layer.js:73:5)
at trim_prefix (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:315:13)
at /Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:335:12)
at Immediate.next (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:275:10)
at Immediate.<anonymous> (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:635:15)
at runCallback (timers.js:706:11)
at tryOnImmediate (timers.js:676:5)
at processImmediate (timers.js:658:5)
当Mongoose在设计模型/架构时提供时,我什至需要这个吗?
var mongoose = require('mongoose')
var emailValidator = require('email-validator')
var bcrypt = require('bcrypt') // hashing function dedicated for passwords
const SALT_ROUNDS = 12
var UserSchema = new mongoose.Schema(
{
username_email: {
type: String,
required: true,
lowercase: true,
index: { unique: true }, // I mean this!
validate: {
validator: emailValidator.validate,
message: props => `${props.value} is not a valid email address`
}
},
password: {
type: String,
required: true,
trim: true,
index: { unique: true },
minlength: 8
}
},
{
timestamps: true
}
)
UserSchema.pre('save', async function preSave(next) {
var user = this
var hash
if (!user.isModified('password')) return next()
try {
hash = await bcrypt.hash(user.password, SALT_ROUNDS)
user.password = hash
return next()
} catch (err) {
return next(err)
}
})
UserSchema.methods.comparePassword = async function comparePassword(candidate) {
return bcrypt.compare(candidate, this.password)
};
module.exports = mongoose.model('User', UserSchema)
如果我不这样做,那意味着检查电子邮件是否存在应该移到前端?如果是这种情况,我将如何处理呢?
更新
我尝试了尼克的建议,但不确定为什么我仍然得到
`Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
` 这些是更新的路线:
router
.route('/registration')
.get(function(req, res) {
console.log(0)
UserModel.find({}, (err, users) => {
console.log(1)
if (err) res.status(500).send(err)
console.log(2)
return res.json(users)
console.log(3)
})
})
.post(body('email').custom(value => {
console.log(4)
UserModel.findOne({ 'email': value }).then(user => {
console.log(5)
if (user) {
console.log(6)
return Promise.reject('E-mail already in use');
}
});
}), async(req, res, next) => {
console.log(7)
try {
let newUser = new UserModel(req.body)
let savedUser = await newUser.save(err => {
if (err) return res.json({ success: false, error: err })
console.log(8)
return res.json({ success: true })
})
console.log(9)
if (savedUser) return res.redirect('/users/registration?success=true');
console.log("savedUser ", savedUser);
console.log(10)
return next(new Error('Failed to save user for unknown reasons'))
} catch (err) {
return next(err)
}
})
Note that pages will be compiled when you first load them.
GET /_next/static/webpack/d691821e71bf01c860e6.hot-update.json 404 299.194 ms - 1862
GET /_next/static/webpack/42c7a9cb77dec12fc8a3.hot-update.json 200 40.276 ms - 35
4
7
9
savedUser undefined
10
POST /users/registration 200 21.490 ms - 422
Error: Failed to save user for unknown reasons
at router.route.get.post (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/server/users/index.js:42:25)
at process._tickCallback (internal/process/next_tick.js:68:7)
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:470:11)
at ServerResponse.header (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/response.js:767:10)
at ServerResponse.send (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/response.js:267:15)
at /Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/server/index.js:108:17
at Layer.handle_error (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/layer.js:71:5)
at trim_prefix (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:315:13)
at /Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:335:12)
at next (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:275:10)
at Layer.handle_error (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/layer.js:73:5)
at trim_prefix (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:315:13)
at /Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:335:12)
at Immediate.next (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:275:10)
at Immediate.<anonymous> (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/express/lib/router/index.js:635:15)
at runCallback (timers.js:706:11)
at tryOnImmediate (timers.js:676:5)
at processImmediate (timers.js:658:5)
5
6
(node:68936) UnhandledPromiseRejectionWarning: E-mail already in use
(node:68936) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:68936) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
^C
答案 0 :(得分:1)
错误“错误[ERR_HTTP_HEADERS_SENT]:将标头发送到客户端后无法设置标头”表示在请求期间多次触发了res.send / json / redirect。乍一看,此代码块有可能导致此错误。
.get(function(req, res) {
UserModel.find({}, (err, users) => {
if (err) res.status(500).send(err)
res.json(users)
})
})
在没有仔细考虑发出的确切请求的情况下,我建议将console.log行放在任何地方,以查看是否可以查明运行时发生的情况。
更新
.get(function(req, res) {
UserModel.find({}, (err, users) => {
// If there's an error, this will fire and continue
if (err) res.status(500).send(err)
// This fires next even if there is an error
res.json(users)
})
})
这可能是导致该问题的原因。可能会触发两次。解决办法是增加回报。这样可以确保代码不会继续。
.get(function(req, res) {
UserModel.find({}, (err, users) => {
if (err) return res.status(500).send(err)
return res.json(users)
})
})
如果这不能解决问题,建议您将console.log语句放在所有自变量后面,以便您查明失败的行。例如:
router
.route('/registration')
.get(function(req, res) {
console.log(0)
UserModel.find({}, (err, users) => {
console.log(1)
if (err) res.status(500).send(err)
console.log(2)
res.json(users)
console.log(3)
})
})
.post(body('username').custom(value => {
console.log(4)
UserModel.findOne({ 'email': value }).then(user => {
console.log(5)
if (user) {
console.log(6)
return Promise.reject('E-mail already in use');
}
});
}), async(req, res, next) => {
console.log(7)
try {
let newUser = new UserModel(req.body)
let savedUser = await newUser.save(err => {
if (err) return res.json({ success: false, error: err })
console.log(8)
return res.json({ success: true })
})
console.log(9)
if (savedUser) return res.redirect('/users/registration?success=true');
console.log(10)
return next(new Error('Failed to save user for unknown reasons'))
} catch (err) {
return next(err)
}
})