React表单提交用户注册API返回400 Bad Request问题排查
注册表单提交失败问题排查
问题背景
用户注册POST API在Postman测试正常,但通过React组件提交时,后端返回三个字段的验证错误:
- Name is required
- Please include a valid email
- Please enter a password with 6 or more characters
后端API路由代码
router.post('/', [ check('name', 'Name is required') .not() .isEmpty(), check('email', 'Please include a valid email').isEmail(), check('password', 'Please enter a password with 6 or more characters').isLength({ min: 6 }) ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); //400 is for bad requests } const { name, email, password } = req.body; try { //See if user exists let user = await User.findOne({ email }); if (user) { return res.status(400).json({ errors: [{ msg: 'User already exists' }] }); } //Get users gravatar const avatar = gravatar.url(email, { s: '200', r: 'pg', d: 'mm' }) user = new User({ name, email, avatar, password }); //Encrypt password const salt = await bcrypt.genSalt(10); user.password = await bcrypt.hash(password, salt); await user.save(); //Return jsonwebtoken -> this for users to be logged in right after registration const payload = { user: { id: user.id } } jwt.sign( payload, config.get('jwtSecret'), { expiresIn: 360000 }, //change to 3600 for production (err, token) => { if (err) throw err; res.json({ token }); } ) } catch (err) { console.error(err.message); res.status(500).send('Server Error'); } }); module.exports = router;
React组件代码
import React, { useState } from 'react' import axios from 'axios' //Material UI import {Grid, Container, Box, Button, FormControl, InputLabel, Input, FormHelperText } from '@mui/material' function Register() { const [ formData, setFormData ] = useState({ name: '', email: '', password: '', password2: '' }) const { name, email, password, password2 } = formData; const onChange = e => setFormData({...formData, [e.target.name]: e.target.value}) const onSubmit = async (e) => { e.preventDefault(); if(password !== password2){ console.log("Passwords do not match"); } else { const newUser = { name: "", email: "", password: "" } try { const config = { headers: { 'Content-Type': 'application/json' } } const body = JSON.stringify(newUser); const res = await axios.post('http://localhost:3000/api/users', body, config) console.log(res.data) } catch (error) { console.error(error.response.data) } } } return ( <Container> <Box p={4}> <Grid container > <form onSubmit={e => onSubmit(e)}> <Grid item md={12}> <FormControl> <InputLabel htmlFor="name">Name</InputLabel> <Input type='text' id='name' name='name' value={name} onChange={e => onChange(e)} /> <FormHelperText>Insert your complete name</FormHelperText> </FormControl> </Grid> <Grid item md={12}> <FormControl> <InputLabel htmlFor="email">Email</InputLabel> <Input id='email' type='email' name='email' value={email} onChange={e => onChange(e)} /> <FormHelperText>Insert your email</FormHelperText> </FormControl> </Grid> <Grid item md={12}> <FormControl> <InputLabel htmlFor="password">Password</InputLabel> <Input id="password" type='password' name='password' value={password} onChange={e => onChange(e)} /> <FormHelperText>Insert your password (must have at least 6 characters)</FormHelperText> </FormControl> </Grid> <Grid item md={12}> <FormControl> <InputLabel htmlFor="password2">Confirm Password</InputLabel> <Input id="password2" type='password' name='password2' value={password2} onChange={e => onChange(e)} /> <FormHelperText>Insert your password (must have at least 6 characters)</FormHelperText> </FormControl> </Grid> <Grid item md={12}> <Button type='submit' variant="contained" color="primary"> Register </Button> </Grid> </form> </Grid> </Box> </Container> ) } export default Register
错误信息
{ "errors": [ { "msg": "Name is required", "param": "name", "location": "body", "value": "" }, { "msg": "Please include a valid email", "param": "email", "location": "body" }, { "msg": "Please enter a password with 6 or more characters", "param": "password", "location": "body" } ] }
问题原因
核心错误在于React组件的onSubmit函数中,你创建的newUser对象是硬编码的空字符串,并没有使用表单中用户输入的formData数据。这导致后端接收的请求体全是空值,触发了字段验证错误。
修复方案
修改onSubmit函数中的newUser定义,直接使用状态中的表单数据:
const onSubmit = async (e) => { e.preventDefault(); if(password !== password2){ console.log("Passwords do not match"); } else { // 从formData中提取需要的字段,排除password2 const newUser = { name: name, email: email, password: password } try { const config = { headers: { 'Content-Type': 'application/json' } } // axios支持直接传入对象,无需手动JSON.stringify const res = await axios.post('http://localhost:3000/api/users', newUser, config) console.log(res.data) } catch (error) { console.error(error.response.data) } } }
或者更简洁的解构写法:
const newUser = { name, email, password };
另外,axios默认会将JavaScript对象序列化为JSON并设置Content-Type: application/json,所以你可以省略手动设置config的步骤,进一步简化代码:
try { const res = await axios.post('http://localhost:3000/api/users', newUser) console.log(res.data) } catch (error) { console.error(error.response.data) }
内容的提问来源于stack exchange,提问作者tukitooo1998
相关产品推荐
相关产品推荐

