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

Next.js使用变量提交数据至MongoDB失败,硬编码则正常

问题排查:Next.js表单数据无法存入MongoDB,硬编码数据可正常存储

背景信息

正在学习新技术,开发Next.js前端项目,Express后端已通过Postman测试,所有API端点正常工作。使用MongoDB作为数据库,已配置cors。

问题现象

  • 通过表单收集employeeData发起POST请求时,控制台打印employeeData所有字段均存在且正确,但数据无法存入MongoDB,后端返回状态码200
  • 使用硬编码的formData发起相同POST请求时,数据可正常存入数据库

相关代码

表单提交的请求代码

try {
   const response = await fetch('http://localhost:8080/api/v1/employee', {
      method: 'POST',
      headers: {
         'Content-Type': 'application/json',
      },
      body: JSON.stringify(employeeData),
   });
      
   if (response.ok) {
      console.log('Employee saved successfully');
   } else {
      console.error('Error saving employee:', response.statusText);
      console.log('Response Body:', await response.json());
   }
} catch (error) {
   console.error('Error saving employee:', error);
}

硬编码成功的请求代码

const formData = {
   name: 'John',
   surname: 'Doe',
   telephone: '0123456789',
   email: 'johndoe@gmail.com',
   manager: 'Manager A',
   status: true,
};

try {
   const response = await fetch('http://localhost:8080/api/v1/employee', {
      method: 'POST',
      headers: {
         'Content-Type': 'application/json',
      },
      body: JSON.stringify(formData),
   });
      
   if (response.ok) {
      console.log('Employee saved successfully');
   } else {
      console.error('Error saving employee:', response.statusText);
      console.log('Response Body:', await response.json());
   }
} catch (error) {
   console.error('Error saving employee:', error);
}

完整addEmployee.tsx代码

import React, { useState, useEffect } from 'react';
import Container from '@mui/material/Container';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';
import Select from '@mui/material/Select';
import MenuItem from '@mui/material/MenuItem';
import InputLabel from '@mui/material/InputLabel';
import FormControl from '@mui/material/FormControl';
import axios from 'axios';

import MenuBar from '@/components/MenuBar';
import { useRouter } from 'next/router';

export default function addEmployee() {
    const router = useRouter();
    const [managerOptions, setManagerOptions] = useState([]);
    const [employeeData, setEmployeeData] = useState({
        name: '',
        surname: '',
        telephone: '',
        email: '',
        manager: '',
    });

    useEffect(() => {
        axios
        .get('http://localhost:8080/api/v1/employee')
            .then((response) => {
                console.log('Employee data:', response.data);
                setManagerOptions(
                    response.data.map(
                    (employee) => `${employee.name} ${employee.surname}`
                    )
                );
            })
        .catch((error) => {
            console.error('Error fetching employee data:', error);
        });
    }, []);

    const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        const { name, value } = event.target;
        setEmployeeData((prevData) => ({ ...prevData, [name]: value }));
    };

    const handleManagerChange = (event: React.ChangeEvent<{ value: unknown }>) => {
        setEmployeeData((prevData) => ({ ...prevData, manager: event.target.value as string }));
    };

    const handleButtonClick = async (option: string) => {
        switch (option) {
            case 'Save':

                if(employeeData.name === '' || employeeData.surname === '' || employeeData.telephone === '' || employeeData.email === '') {
                    alert("Required fields are not filled in!");
                    break;
                };

                try {
                    const response = await fetch('http://localhost:8080/api/v1/employee', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                        },
                        body: JSON.stringify(employeeData),
                    });
      
                    if (response.ok) {
                      console.log('Employee saved successfully');
                      console.log(response);
                    } else {
                      console.error('Error saving employee:', response.statusText);
                      console.log('Response Body:', await response.json());
                    }
                } catch (error) {
                    console.error('Error saving employee:', error);
                }
                router.push('/employee');
                break;
            case 'Cancel':
                router.push('/employee');
                break;
            default:
                break;
        }
    };

    return (
        <Container>
            <MenuBar />
            
            <Container maxWidth="md">
                <Box mt={4} mb={2}>
                <Typography variant="h5">Create Employee</Typography>
                </Box>
                <Box border={1} borderColor="grey.400" p={2} borderRadius={4}>
                <form>
                    <Box mb={2}>
                        <TextField label="Name*" fullWidth name="name" onChange={handleInputChange} />
                    </Box>
                    <Box mb={2}>
                        <TextField label="Surname*" fullWidth name="surname" onChange={handleInputChange} />
                    </Box>
                    <Box mb={2}>
                        <TextField label="Telephone Number*" fullWidth name="telephone" onChange={handleInputChange} />
                    </Box>
                    <Box mb={2}>
                        <TextField label="Email Address*" fullWidth name="email" onChange={handleInputChange} />
                    </Box>
                    <Box mb={2}>
                        <FormControl fullWidth>
                        <InputLabel>Manager</InputLabel>
                        <Select
                            value={employeeData.manager}
                            onChange={handleManagerChange}
                            displayEmpty
                        >
                            {managerOptions.map(manager => (
                                <MenuItem key={manager} value={manager}>
                                {manager}
                                </MenuItem>
                            ))}
                        </Select>
                        </FormControl>
                    </Box>
                    <Button type="button" variant="contained" color="inherit" onClick={() => handleButtonClick('Save')}>
                        Save
                    </Button>
                    <Button variant="contained" color="inherit" onClick={() => handleButtonClick('Cancel')}>
                        Cancel
                    </Button>
                </form>
                </Box>
            </Container>
        </Container>
    );
}

问题分析与解决方案

1. 缺失status字段

对比硬编码的formData和表单的employeeData,发现硬编码数据包含status: true,但表单的employeeData初始状态没有status字段,提交时也不会携带该字段。若MongoDB的Employee Schema中status是必填字段(即使有默认值,前端未传可能导致后端处理异常),会出现数据无法存入但返回200的情况(后端可能未做严格校验,直接返回成功但数据库未写入)。

解决方案:
在employeeData的初始状态中添加status字段,默认设为true:

const [employeeData, setEmployeeData] = useState({
    name: '',
    surname: '',
    telephone: '',
    email: '',
    manager: '',
    status: true, // 添加该字段
});

2. 路由跳转过早

当前代码中,fetch请求是异步操作,但在try/catch块之后立即执行router.push('/employee'),可能导致请求还未完成就跳转到其他页面,虽浏览器会继续完成请求,但如果后端处理依赖前端后续状态,或请求被意外中断,也可能导致数据未写入。

解决方案:
将router.push移到response.ok的判断分支内,确保请求成功后再跳转:

try {
    const response = await fetch('http://localhost:8080/api/v1/employee', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(employeeData),
    });

    if (response.ok) {
        console.log('Employee saved successfully');
        console.log(response);
        router.push('/employee'); // 移到此处
    } else {
        console.error('Error saving employee:', response.statusText);
        console.log('Response Body:', await response.json());
    }
} catch (error) {
    console.error('Error saving employee:', error);
}
// 移除此处的router.push

3. 后端字段校验问题

如果后端Schema中某些字段有格式校验(比如telephone的格式、email的格式),表单输入的数据可能不符合校验规则,但后端返回了200(比如错误处理不当,未返回错误状态码)。

验证方法:
在控制台打印employeeData的具体值,和硬编码的formData对比,检查字段格式是否一致。比如telephone是否是字符串类型、email是否符合邮箱格式。

解决方案:

  • 在前端添加字段格式校验,确保输入符合后端要求
  • 检查后端错误处理逻辑,确保不符合校验的数据返回非200状态码,并返回错误信息

内容的提问来源于stack exchange,提问作者Jandrie Visagie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 22:50:57