You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 16:04:54