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

React登录组件调用Express API报500错误,需实现登录成功跳转

问题解决:登录API 500错误修复及登录跳转实现

核心错误原因(500 Internal Server Error)

你的Express后端代码存在两个致命问题:

  • 未定义JWT生成函数:代码中调用了generateAccessToken和generateRefreshToken,但这两个函数完全没实现,直接导致服务器抛出异常。
  • 错误的响应方法:使用了res.status(200).alert(),Express的Response对象没有alert方法,这会触发服务器报错。

修复后的后端代码

const express = require('express');
const app = express();
const jwt = require('jsonwebtoken');
app.use(express.json());

// 建议生产环境将密钥存入环境变量,此处用测试密钥示例
const ACCESS_TOKEN_SECRET = 'your-access-token-secret-key';
const REFRESH_TOKEN_SECRET = 'your-refresh-token-secret-key';

let refreshTokens = [];

const users = [
  {
    id: "1",
    username: "nacer",
    email: "user1@example.com",
    password: "password1",
    isAdmin: true,
  },
  {
    id: '2',
    username: 'imane',
    email: 'user2@example.com',
    password: 'password2',
    isAdmin: false,
  },
];

// 实现缺失的JWT生成函数
function generateAccessToken(user) {
  return jwt.sign({ id: user.id, isAdmin: user.isAdmin }, ACCESS_TOKEN_SECRET, { expiresIn: '15m' });
}

function generateRefreshToken(user) {
  return jwt.sign({ id: user.id, isAdmin: user.isAdmin }, REFRESH_TOKEN_SECRET);
}

app.post('/api/login', (req, res) => {
  const { email, password } = req.body;
  const user = users.find(u => u.email === email && u.password === password);
  
  if (user) {
    const accessToken = generateAccessToken(user);
    const refreshToken = generateRefreshToken(user);
    refreshTokens.push(refreshToken);
    
    res.cookie('accessToken', accessToken, { httpOnly: true });
    res.cookie('refreshToken', refreshToken, { httpOnly: true });
    
    // 替换错误的alert方法,用json返回响应
    res.status(200).json({
      message: 'Login successful! Thank you for joining us!'
    });
    // 移除后端重定向,前端axios请求无法处理该跳转,逻辑移至前端
  } else {
    res.status(400).json({ message: 'username or password incorrect! ' });
  }
});

app.listen(5000, () => {
  console.log('Server started on port 5000');
});

前端代码优化(修复跳转及错误提示)

  1. 使用React Router的useNavigate实现SPA路由跳转,比window.location.href更符合单页应用逻辑
  2. 在catch块中触发错误提示,支持显示后端返回的具体错误信息
  3. 优化表单输入的双向绑定逻辑
import React, { useState } from 'react'
import './Login.css'
import { Form, Row, Col, Button } from 'react-bootstrap';
import { BiLogIn } from 'react-icons/bi'
import axios from 'axios';
// 引入React Router的导航钩子
import { useNavigate } from 'react-router-dom';

const Login = () => {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const [error, setError] = useState('');
    // 初始化导航实例
    const navigate = useNavigate();

    const handleSubmit = async (event) => {
        event.preventDefault();
        // 重置错误信息
        setError('');

        try {
            const res = await axios.post('/api/login', { email, password });
            alert(res.data.message);
            // 使用React Router跳转至Books页面
            navigate('/Books');
        } catch (err) {
            console.error(err);
            // 设置后端返回的错误信息,无返回时用默认提示
            setError(err.response?.data?.message || 'Login failed, please try again.');
        }
    };

    const login_font = new URL('../../assets/login-font.jpg', import.meta.url);
    
    return (
        <div>
            <img src={login_font} className='login-font' alt='Login background' />
            <center>
                <span className='login'>
                    <h2><b><BiLogIn /> Login</b></h2> <br />
                    <Form onSubmit={handleSubmit}>
                        <Form.Group className="mb-3" controlId="formGroupEmail">
                            <Form.Label><b>Email address</b></Form.Label>
                            {/* 绑定value实现双向绑定 */}
                            <Form.Control 
                                type="email" 
                                placeholder="Enter email" 
                                value={email}
                                onChange={(e) => setEmail(e.target.value)} 
                            />
                        </Form.Group>
                        <Form.Group className="mb-3" controlId="formGroupPassword">
                            <Form.Label><b>Password</b></Form.Label>
                            <Form.Control 
                                type="password" 
                                placeholder="Password" 
                                value={password}
                                onChange={(e) => setPassword(e.target.value)} 
                            />
                        </Form.Group>
                        <Form.Group as={Row} className="mb-3" controlId="formHorizontalCheck">
                            <Col sm={{ span: 5, offset: 3 }}>
                                <Form.Check label="Remember me" />
                            </Col>
                        </Form.Group>
                        <div className="d-grid gap-2">
                            <Button type='submit' variant="primary" size="smx" >Login</Button>
                        </div>
                        {error && (
                            <div className="text-danger mt-3">
                                {error}
                            </div>
                        )}
                    </Form>
                </span>
            </center>
        </div>
    )
}

export default Login

额外注意事项

  1. 确保后端服务运行在5000端口,前端服务在3000端口,你的package.json中proxy: "http://localhost:5000"配置正确,会自动转发API请求。
  2. JWT密钥需设置为安全的随机字符串,生产环境不要硬编码,建议使用环境变量(如process.env.ACCESS_TOKEN_SECRET)。
  3. 前端错误提示从布尔值改为字符串,可显示更具体的错误内容。

内容的提问来源于stack exchange,提问作者Chouich Nacereddine

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 20:42:26