React+SpringBoot+Spring Security中Axios出现ERR_TOO_MANY_REDIRECTS错误求助
问题描述
我是React新手,后端用SpringBoot+Spring Security搭建,尝试通过React前端发起简单的GetMapping请求。后端已实现Spring Security,所以先通过React的Login组件获取JWT令牌并存入localStorage(仅练习用),获取令牌后登录页跳转到HomePage,由Axios发起GetMapping请求,另有组件自动为每个请求添加令牌到请求头。
用Postman测试一切正常:登录认证的PostMapping返回令牌,携带令牌的GetMapping返回数据,但进入HomePage后却出现net:ERR_TOO_MANY_REDIRECTS错误。未实现安全模块时,HomePage可以正常显示数据。
登录页(获取JWT令牌)代码
import axios from 'axios'; import React, { useState } from 'react' import { Link, useNavigate } from 'react-router-dom'; export default function LoginPage() { let navigate = useNavigate(); const [user, setUsers] = useState({ username:"", password:"" }); const onInputChange = (e) =>{ setUsers({...user, [e.target.name]:e.target.value}); }; const handleSubmit = async (e) => { e.preventDefault(); try { const response = await axios.post("http://localhost:8082/api/v1/auth/signin", user); const { token } = response.data; localStorage.setItem('token', token); } catch (error) { } }; return ( <div className='container'> {/*make a container*/} <div className='row'> <div className='col-md-6 offset-md-3 border rounded p-4 mt-2 shadow'> <h2 className='text-center m-4'> HRMasery Login</h2> {/*container title*/} <form onSubmit={handleSubmit}> {/*when submit -> trigger onSubmit function */} <div className='mb-3'> <label htmlFor="Name" className='form-label'> {/*for label */} UserName </label> {/*when user inputs, type string, assigned to name*/} <input type={"text"} name="username" className='form-control' value={user.username} onChange={onInputChange} placeholder='Enter Username' /> </div> <div className='mb-3'> <label htmlFor="jobTitle" className='form-label'> Password </label> <input type={"text"} name="password" className='form-control' value={user.password} onChange={onInputChange} placeholder='Password' /> </div> <Link type='submit' className='bnt btn-outline-primary' to={'/homepage'}> {/*submit button is submit class */} Login </Link> </form> </div> </div> </div> ) }
请求拦截器(添加JWT到请求头)代码
import axios from 'axios'; const api = axios.create({ baseURL: 'http://localhost:8082', }); // Add a request interceptor api.interceptors.request.use( (config) => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => Promise.reject(error) ); export default api
HomePage(发起GetMapping请求)代码
import React, { useEffect, useState } from 'react'; import axios from 'axios'; import {Link, useParams} from "react-router-dom"; import Navbar from '../Layout/Navbar'; import api from '../api'; export default function HomePage_Manager() { const[users, setUsers] = useState([]) let JWT = localStorage.getItem('token'); useEffect(() => { const fetchProfile = async () => { try { const response = await api.get('/allemployee'); setUsers(response.data); } catch (error) { } }; fetchProfile(); }, []); return ( <div className='container'> <div className='py-4'> <table className="table border shadow"> {/*make table inside the container*/} <thead> <tr> {/*colum names inside the table*/} <th scope="col">#</th> <th scope="col">ID</th> <th scope="col">Name</th> <th scope="col">Email</th> <th scope="col">PhoneNumber</th> <th scope="col">Job Title</th> <th scope="col">Annual Salary</th> </tr> </thead> <tbody> {users.map((user, index) => ( <tr> <th scope="row" key={index}> {index+1} </th> <td>{user.id}</td> <td>{user.name}</td> <td>{user.email}</td> <td>{user.phoneNumber}</td> <td>{user.jobTitle}</td> <td>${user.annualSalary}</td> <td> <Link className='btn btn-primary mx-2' to={`/viewstaff/${user.id}`}> View Employee </Link> <Link className='btn btn-outline-primary mx-2' to={`/editstaff/${user.id}`}> Edit Employee </Link> </td> </tr> )) } </tbody> </table> </div> </div> ) }
错误原因分析
- 登录逻辑失效:登录页的“Login”按钮用了
<Link>组件,点击后直接跳转至/homepage,但不会触发表单的onSubmit事件,也就不会执行handleSubmit去后端获取JWT令牌。此时localStorage无有效令牌,HomePage发起请求时请求头未携带JWT,后端Spring Security判定未认证,会重定向到登录页面;前端路由又可能因未登录状态跳回HomePage,形成循环重定向,导致ERR_TOO_MANY_REDIRECTS。 - 后端配置冲突:Spring Security默认对未认证请求执行重定向操作,但前端是单页应用,重定向会与前端路由逻辑冲突,进一步加剧循环重定向问题。
解决方案
1. 修复登录页提交逻辑
将<Link>替换为<button>组件,确保点击登录按钮时触发表单提交,获取JWT令牌后再跳转至HomePage:
// 修正handleSubmit函数,添加跳转逻辑 const handleSubmit = async (e) => { e.preventDefault(); try { const response = await axios.post("http://localhost:8082/api/v1/auth/signin", user); const { token } = response.data; localStorage.setItem('token', token); // 获取令牌后再跳转 navigate('/homepage'); } catch (error) { console.error('登录失败:', error); // 可在此添加错误提示,如用户名密码错误 } }; // 替换原Login按钮 <button type='submit' className='btn btn-outline-primary'> Login </button>
2. 调整后端Spring Security配置
针对单页应用,后端需对未认证的API请求返回401 Unauthorized,而非重定向。修改Spring Security配置类:
@Override protected void configure(HttpSecurity http) throws Exception { http // 其他配置... .exceptionHandling() .authenticationEntryPoint((request, response, authException) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); }); }
3. 完善前端错误处理
在HomePage的请求中添加错误处理,便于排查问题并处理未认证场景:
useEffect(() => { const fetchProfile = async () => { try { const response = await api.get('/allemployee'); setUsers(response.data); } catch (error) { console.error('获取数据失败:', error); // 若返回401,说明令牌无效或未登录,清除令牌并跳回登录页 if (error.response?.status === 401) { localStorage.removeItem('token'); navigate('/login'); } } }; fetchProfile(); }, [navigate]);
4. 前端路由守卫(可选)
添加路由守卫,限制未登录用户访问HomePage,直接跳转至登录页:
// 定义路由守卫组件 import { Navigate } from 'react-router-dom'; const ProtectedRoute = ({ children }) => { const token = localStorage.getItem('token'); if (!token) { return <Navigate to="/login" replace />; } return children; }; // 在路由配置中使用 <Route path="/homepage" element={<ProtectedRoute><HomePage_Manager /></ProtectedRoute>} />
内容的提问来源于stack exchange,提问作者jxie5189
相关产品推荐
相关产品推荐

