node.js - ValidationError:用户验证失败:username_email:需要路径“username_email”。使用 express 验证器、next.js、express 和 mogoose
问题描述
我正在尝试在保存之前使用express-validator搜索 mongodb 以查看是否存在电子邮件。
这是我的路线的摘录:
.post(body('username').custom(value => {
return UserModel.findOne({ 'username_email': value }).then(user => {
if (user) {
return Promise.reject('E-mail already in use');
}
});
但我收到了这个错误:
ValidationError: User validation failed: username_email: Path `username_email` is required.
at new ValidationError (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/mongoose/lib/error/validation.js:30:11)
at model.Document.invalidate (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/mongoose/lib/document.js:2292:32)
at p.doValidate.skipSchemaValidators (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/mongoose/lib/document.js:2141:17)
at /Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/mongoose/lib/schematype.js:1037:9
at process._tickCallback (internal/process/next_tick.js:61:11)
POST /users/registration 500 29.796 ms - 51
这是我的完整路线:
var router = require('express').Router()
var UserModel = require('../models/UserModel')
var { body } = require('express-validator');
router
.route('/registration')
.get(function(req, res) {
// req.session.visits = req.session.visits ? req.session.visits + 1 : 1
UserModel.find({}, (err, users) => {
if (err) res.status(500).send(err)
res.json(users)
})
})
.post(body('username').custom(value => {
return UserModel.findOne({ 'username_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()
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
这是我的架构/模型:
/* eslint-disable no-var */
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 },
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)
为了更好地衡量,这是我的组件:
import React, { Component } from 'react'
import { Transition, Button, Form, Grid, Header, Message, Segment } from 'semantic-ui-react'
class Register extends Component {
constructor(props) {
super(props)
this.state = {
fadeUp: 'fade up',
isLoggedIn: true,
duration: 500,
isVisible: false,
username: '',
password: '',
usernameError: false,
passwordError: false,
formError: true,
formSuccess: false
}
this.handleChange = this.handleChange.bind(this)
this.handleBlur = this.handleBlur.bind(this)
this.handleIsLoggedInClick = this.handleIsLoggedInClick.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event) {
var { name, value } = event.target
this.setState({
[name]: value
})
}
handleIsLoggedInClick() {
this.state.isLoggedIn = this.state.isLoggedIn ? this.setState({ isLoggedIn: true }) : this.setState({ isLoggedIn: false })
}
handleBlur() {
var { username, password, usernameError, passwordError } = this.state
var mailFormat = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
var error = false
if ((!username.match(mailFormat)) && (!usernameError)) {
this.setState({ usernameError: true })
error = true
} else {
this.setState({ usernameError: false })
}
}
handleSubmit(event) {
event.preventDefault()
var { username, password } = this.state
var mailFormat = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
var error = false
if (!username.match(mailFormat)) {
this.setState({ usernameError: true })
error = true
} else {
this.setState({ usernameError: false })
}
if (password.length <= 8) {
this.setState({ passwordError: true })
error = true
} else {
this.setState({ passwordError: false })
}
console.log(`error ${error}`)
if (error == false) {
this.setState({ formError: false, formSuccess: true })
}
window.fetch('http://localhost:8016/users/registration', {
method: 'POST',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({ email: username, password: password })
}).then(function (response) {
console.log(`response ${response}`)
return response.json()
}).then(function (data) {
console.log('User created:', data)
})
}
render() {
var { username, password, usernameError, passwordError, formError, formSuccess, isLoggedIn } = this.state
return (<div className='login-form' > {
/*
Heads up! The styles below are necessary for the correct render of this example.
You can do same with CSS, the main idea is that all the elements up to the `Grid`
below must have a height of 100%.
*/
} <style > {`body > div, body > div > div, body > div > div > div.login-form { height: 100%;}`} </style>
<Grid textAlign='center' style={{ height: '100%' }} verticalAlign='middle'>
<Grid.Column style={{ maxWidth: 450 }}>
<Header as='h2' color='teal' textAlign='center' > {isLoggedIn ? `Register for an account` : ` Log-in to your account`}</Header>
<Form size='large' onSubmit={this.handleSubmit} error={(formError || formSuccess) || usernameError || passwordError} success={!formError && !formSuccess}>
<Segment stacked >
<Form.Input fluid icon='user'
iconPosition='left'
placeholder='E-mail address, e.g. joe@schmoe.com'
name='username'
value={username}
onBlur={this.handleBlur}
onChange={this.handleChange}
error={usernameError}
/>
<Transition visible={usernameError} animation='scale' duration={500}>
<Message error content='Email is in incorrect format e.g. joe@schmoe.com' />
</Transition>
<Form.Input fluid icon='lock'
iconPosition='left'
placeholder='Password'
name='password'
value={password}
onChange={this.handleChange}
error={passwordError}
/>
<Transition visible={passwordError} animation='scale' duration={500} >
<Message error content='Paswword needs to be greater than eight characters.' />
</Transition>
<Button color='teal' fluid size='large' disabled={!this.state.username || !this.state.password} > {isLoggedIn ? `Register` : `Log-in`} </Button>
<Transition visible={(!formError && formSuccess)} animation='scale' duration={500} >
<Message success header='Your user registration was successful' content='You may now log-in with the username you have chosen' />
</Transition>
</Segment>
</Form>
{
!isLoggedIn
? <Message >
New to us ?
<a onClick={this.handleIsLoggedInClick}
href='#' > Register! </a> </Message> : <Message >
<a onClick={this.handleIsLoggedInClick}
href='#' > Back to Login </a> </Message>
} </Grid.Column> </Grid> </div>
)
}
}
export default Register
解决方案
看起来你的代码中有错字。当您向后端发出请求时,您将附加以下正文:
body: JSON.stringify({ email: username, password: password })
哪个有email
参数。然后,在您的验证器中,您正在尝试验证username
prop。
.post(body('username').custom(value => {
并且username
在那里未定义。
所以,你必须遵循一个单一的命名约定,它应该可以工作。
推荐阅读
- excel - 如何参考另一个单元格突出显示一个单元格?
- ios - pod 框架未在 ios 13.3.1 中加载
- reactjs - 在 React 中,当我进行 get 调用时,为什么数据不会自动到来,如果我刷新页面,那么只有数据会到来?
- node.js - 使用生成的 *_pb.js 文件时,如何从 NodeJS 客户端调用 gRPC 服务器?
- node.js - 如何在mongodb聚合中舍入一个值
- spring - 在 Dialogflow 中管理上下文
- java - 如何在Java中制作(有效的)指针
- javascript - 如何在带有状态的新窗口中打开 props.history.push()
- c++ - 使用归纳法查找递归函数的时间复杂度
- c++ - C ++合并排序的链表未对前两个索引进行排序