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

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>
  )
}

错误原因分析

  1. 登录逻辑失效:登录页的“Login”按钮用了<Link>组件,点击后直接跳转至/homepage,但不会触发表单的onSubmit事件,也就不会执行handleSubmit去后端获取JWT令牌。此时localStorage无有效令牌,HomePage发起请求时请求头未携带JWT,后端Spring Security判定未认证,会重定向到登录页面;前端路由又可能因未登录状态跳回HomePage,形成循环重定向,导致ERR_TOO_MANY_REDIRECTS。
  2. 后端配置冲突: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:22:04