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

添加控制器后React登录表单向后端传空数据,求排查

问题:添加控制器后登录请求后端收到空数据

原本正常运行的前后端登录系统,在添加控制器优化代码结构后,用户登录时后端接收到空数据对象,无法完成登录流程。


API 代码

index.js

const express = require('express');
const cors = require("cors");
const dotenv = require("dotenv");
const bodyParser = require('body-parser');

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000

app.use(cors());
app.use(express.urlencoded({ extended: true }))
app.use(bodyParser.json());

app.get('/', (req, res) => {
    res.send('Testing')
})

app.use("/api/auth", require("./routes/authRoutes"));

app.listen(PORT, () => {
    console.log("app is running!")
});

authRoutes.js

const express = require('express');
const router = express.Router();
const authControllers = require('../controllers/authControllers');

router.post('/register', authControllers.register);
router.post('/login', authControllers.login);
// router.post("/logout");

module.exports = router

authController.js

const { PrismaClient } = require('@prisma/client');
const express = require("express");
const router = express.Router();
const prisma = new PrismaClient();
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');

const login = async (req, res) => {
  console.log(req.body)
  try {
      const { email, password } = req.body;

      const user = await prisma.user.findUnique({ where: { email: email } });
      if (!user) {return res.status(401).json({ error: "Password or email is incorrect." });}

      const isValidPassword = bcrypt.compareSync(password, user.password);
      if (!isValidPassword) {return res.status(401).json({ error: "Password or email is incorrect." });}

      const accesToken = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: "3h" });

      res.status(200).json({
        status: "OK",
        message: "Login succes",
        token: accesToken,
        user
    });
  } 
  catch (error) {
      console.error(error);
      res.status(401).json({ error: "Password or email is incorrect." });
  }
};

const register = async (req, res) => {
  try {
      const { username, password, email } = req.body;

      const existingUser = await prisma.user.find({ where: { email } });
      if (existingUser) { return res.status(409).json({ error: "This email is already registered." }) }

      const hashedPassword = await bcrypt.hash(password, 10);
      const newUser = await prisma.user.create({
        data: {
          username,
          password: hashedPassword,
          email,
        },
      });

      const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: "3h" });
      res.json({ token });
  } 
  catch (error) {
      console.error(error);
      res.status(500).json({ error: "Internal server error." });
  }
};

module.exports = { register, login };

APP 代码

loginform.js

/* eslint-disable no-unused-vars */
/* eslint-disable react-hooks/exhaustive-deps */
import './login.css'
import InputField from '../InputField';
import Button from '../Button';
import { useEffect, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import ErrorField from '../ErrorField';
import useLogin from '../../../hooks/useLogin';

const LoginForm = () => {

    // Login component

    const [disable, setDisable] = useState(true);

    const { login, error, formValues, setFormValues } = useLogin()

    const handleChange = async (e) => {
        setFormValues({
            ...formValues,
            [e.currentTarget.name]: e.currentTarget.value
        })
    }

    const submitLoginForm = async (e) => {
        e.preventDefault();
        await login();
    }

    useEffect(() => {
        setDisable(!(formValues.email && formValues.password))
    }, [formValues.password, formValues.email]);

    return (
        <div className="login">
            <img src="./logo.svg" />
            <h2>Login</h2>
            {error && <ErrorField className="form-feedback show" value={error} />}
            <InputField placeholder="Email" className="form-input" name="email" type="text" value={formValues.email || ''} onChange={handleChange} />
            <InputField placeholder="Password" className="form-input" name="password" type="password" value={formValues.password || ''} onChange={handleChange} />
            <Button type="submit" input="LOG IN" className={`form-button ${disable ? 'disabled' : ''}`} disabled={disable} onClick={submitLoginForm}/>
            <Link to='/signup' className='signup-link'>No account? Sign up here!</Link>
        </div>
    )
}

export default LoginForm;

useLoginHook.js

import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "../config/axios";
import useAuthContext from "./useAuthContext";

const useLogin = () => {
    const [error, setError] = useState(null)
    const [isLoading, setIsLoading] = useState(null)
    const { dispatch } = useAuthContext()

    const [formValues, setFormValues] = useState({
        email: "",
        password: "",
    })

    const emptyFormValues = {
        email: "",
        password: "",
    }

    const navigate = useNavigate()

    const login = async (formValues) => {
        
        setIsLoading(true)         
        setError(null)
        
        try {
           const response = await axios.post('api/auth/login', formValues);
           console.log(response.data);
           localStorage.setItem("token", response.data.token)
           dispatch({type: 'LOGIN', payload: response})
           setIsLoading(false)
           navigate("/");

        } catch (error) {
            console.log(error.response.data)
            setFormValues(emptyFormValues)
            setIsLoading(false)
            setError(error.response.data.error)
        }
    }

    return { login, isLoading, error, setError, formValues, setFormValues }
}

export default useLogin;

问题排查与解决

核心问题:前端未传递表单数据到登录函数

在useLoginHook.js中,login函数定义时声明了接收formValues参数,但在loginform.js的submitLoginForm函数里调用login()时没有传入该参数,导致login函数内的formValues为undefined,axios发送的请求体为空,后端自然收到空对象。

修复步骤:

  1. 修改loginform.js中的submitLoginForm函数,调用login时传入formValues:
const submitLoginForm = async (e) => {
    e.preventDefault();
    await login(formValues); // 传入表单数据
}
  1. 可选优化:为避免参数遗漏,可将useLoginHook.js中的login函数改为直接使用内部的formValues,无需外部传参:
const login = async () => { // 移除参数
    setIsLoading(true)         
    setError(null)
    
    try {
       const response = await axios.post('api/auth/login', formValues); // 使用内部的formValues
       // ... 其余代码不变
    } catch (error) {
        // ... 其余代码不变
    }
}

这样修改后,loginform.js中的await login()调用就无需传参,逻辑更清晰。

额外发现的后端问题

authController.js的register函数中,生成JWT时使用了未定义的user变量,应该改为刚创建的newUser:

const token = jwt.sign({ userId: newUser.id }, process.env.JWT_SECRET, { expiresIn: "3h" });

内容的提问来源于stack exchange,提问作者Stef Verniers

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 11:24:54