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'); });
前端代码优化(修复跳转及错误提示)
- 使用React Router的
useNavigate实现SPA路由跳转,比window.location.href更符合单页应用逻辑 - 在catch块中触发错误提示,支持显示后端返回的具体错误信息
- 优化表单输入的双向绑定逻辑
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
额外注意事项
- 确保后端服务运行在5000端口,前端服务在3000端口,你的package.json中
proxy: "http://localhost:5000"配置正确,会自动转发API请求。 - JWT密钥需设置为安全的随机字符串,生产环境不要硬编码,建议使用环境变量(如
process.env.ACCESS_TOKEN_SECRET)。 - 前端错误提示从布尔值改为字符串,可显示更具体的错误内容。
内容的提问来源于stack exchange,提问作者Chouich Nacereddine
相关产品推荐
相关产品推荐

