React调用Spring Boot API时Fetch请求失败,CORS问题求助
多次尝试无法将Spring Boot后端的响应数据获取到React组件中,后端在浏览器或Postman中均可正常工作,已尝试在控制器、方法上添加@CrossOrigin注解(设置origins为"*"或"localhost:3000")、通过WebMvcConfigurer Bean全局启用CORS,甚至在配置文件中配置CORS属性,但仍遇到CORS错误,且响应为空,怀疑前端存在问题。
React组件代码
import React, { useState, useEffect } from "react"; import UsersList from "../components/UsersList"; const Users = () => { const [users, updateUsers] = useState(null); useEffect(() => { fetch('http://localhost:8080/users',{ method: "GET", headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Accept': 'application/json' } }) .then(response => response.json()) .then((responseJson) => { updateUsers(responseJson);// responseJson._embedded ??? //the 'users' json payload is embedded in a parent "_embedded" key }) .catch((error) =>{ console.error(error); }) }, []); return <UsersList items={users}/>; } export default Users;
Spring Boot控制器代码
@RestController @RequestMapping("/users") @CrossOrigin(origins="*", allowedHeaders="*") public class UserController { @Autowired private UserRepository userRepository; @CrossOrigin(origins="http://localhost:3000") @GetMapping("/") public List<User> getAllUsers(){ List<User> users = userRepository.findAll(); return users; } }
解决方案
1. 修正请求URL路径
后端类上@RequestMapping("/users") + 方法上@GetMapping("/"),实际接口路径是http://localhost:8080/users/,前端当前请求的http://localhost:8080/users缺少末尾斜杠,会导致路由不匹配,后端无法正确处理请求,进而引发CORS错误或响应为空。
修改前端fetch的URL:
fetch('http://localhost:8080/users/', { ... })
2. 移除前端请求头中的Access-Control-Allow-Origin
Access-Control-Allow-Origin是后端响应头需要返回的字段,前端请求中添加这个头毫无意义,反而可能干扰请求正常发送,直接删除:
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }
3. 处理Spring Data REST的包装结构(若适用)
如果你的UserRepository继承了JpaRepository且项目使用了Spring Data REST,后端返回的JSON会被自动包装在_embedded.users下,此时需要调整前端数据解析逻辑:
.then((responseJson) => { // 若存在_embedded结构,取其中的users数组 const userData = responseJson._embedded?.users || responseJson; updateUsers(userData); })
4. 统一CORS配置
类上和方法上的@CrossOrigin注解重复,容易导致配置冲突,建议只保留类级别的配置,并明确指定前端地址:
@RestController @RequestMapping("/users") @CrossOrigin(origins = "http://localhost:3000", allowedHeaders = "*") public class UserController { @Autowired private UserRepository userRepository; @GetMapping("/") public List<User> getAllUsers(){ List<User> users = userRepository.findAll(); return users; } }
5. 优化前端状态初始化与空值处理
将users的初始状态设为空数组而非null,避免子组件UsersList接收null时出现报错,同时可添加加载状态提示:
const [users, updateUsers] = useState([]); // ... if (users.length === 0) { return <div>加载中...</div>; } return <UsersList items={users}/>;
内容的提问来源于stack exchange,提问作者JK'sScowling

