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

ReactJS+Spring Boot跨域报错:No 'Access-Control-Allow-Origin'问题

跨域问题排查与解决:React + Spring Boot 调用API时出现No 'Access-Control-Allow-Origin' header错误

我使用ReactJS作为前端、Spring Boot作为后端,调用API接口http://localhost:8080/api/v1/admin/member/checkIn?gymId=1&email=xyz@gmail.com时,出现报错:No 'Access-Control-Allow-Origin' header is present on the requested resource。

原ReactJS API调用代码

export const checkInMembers = (gymId, email) => {
    const adminData = JSON.parse(window.sessionStorage.getItem("USER_DETAILS"));
    
    return axios.post('http://localhost:8080/api/v1/admin/member/checkIn', { gymId, email }, {
        headers: {
            'Authorization': `Bearer ${adminData.token}`,
        },
    });
}

Spring Boot后端控制器代码

package com.CMPE202.healthclub.controller;

import com.CMPE202.healthclub.entity.user.User;
import com.CMPE202.healthclub.entity.user.UserGymVisit;
import com.CMPE202.healthclub.exceptions.BadServerException;
import com.CMPE202.healthclub.exceptions.InvalidOperationException;
import com.CMPE202.healthclub.exceptions.RecordNotFoundException;
import com.CMPE202.healthclub.model.UserDetailsResponse;
import com.CMPE202.healthclub.service.AdminService;
import jakarta.annotation.security.RolesAllowed;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/api/v1/admin")
@RequiredArgsConstructor
@CrossOrigin(origins = "*", allowedHeaders = "*")
@RolesAllowed("STAFF")
@Validated
public class AdminController {
    private final AdminService adminService;
    @GetMapping({"/member"})
    public UserDetailsResponse getUserDetailsFromEmail(@RequestParam String email) throws RecordNotFoundException {
        return adminService.getUserDetailsFromEmail(email);
    }
    @PostMapping({"/member/checkIn"})
    public UserGymVisit checkInUserToGym(@RequestParam(required = true) Long gymId,
                                         @RequestParam(required = true) String email) throws RecordNotFoundException, InvalidOperationException, BadServerException {
        return adminService.checkInUsers(gymId, email);
    }
    @PutMapping({"/member/checkOut"})
    public UserGymVisit checkOutUserToGym(@RequestParam(required = true) Long userGymVisitId) throws InvalidOperationException {
        return adminService.checkOutUsers(userGymVisitId);
    }
    @GetMapping({"/member/currentCheckedInList"})
    public List<UserDetailsResponse> getAllCurrentCheckedInUsers(@RequestParam(required = true) Long gymId){
        return adminService.getAllCurrentCheckedInUsers(gymId);
    }
}

尝试过的修改(未解决问题)

export const checkInMembers = (gymId, email) => {
    const adminData = JSON.parse(window.sessionStorage.getItem("USER_DETAILS"));
    const corsOptions = {
        origin: 'http://localhost:8080', // specify the URL of your server
    };

    const axiosInstance = axios.create();
    axiosInstance.interceptors.request.use(cors(corsOptions));
    return axiosInstance.post('http://localhost:8080/api/v1/admin/member/checkIn', { gymId, email }, {
        headers: {
            'Authorization': `Bearer ${adminData.token}`,
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Headers': '*'
        },
        mode: 'cors',
        credentials: 'include'
    });
}

问题根源与解决方法

1. 请求参数传递不匹配

后端checkInUserToGym方法用@RequestParam声明要从URL查询参数中获取gymId和email,但前端是通过POST请求的请求体传递参数,导致后端无法获取到必填参数,触发参数校验失败。这种情况下请求会在进入控制器前被拦截,@CrossOrigin注解的CORS头无法正常返回,最终出现跨域报错。

解决方式二选一:

  • 前端修改为传递URL参数:
export const checkInMembers = (gymId, email) => {
    const adminData = JSON.parse(window.sessionStorage.getItem("USER_DETAILS"));
    
    return axios.post(`http://localhost:8080/api/v1/admin/member/checkIn?gymId=${gymId}&email=${email}`, {}, {
        headers: {
            'Authorization': `Bearer ${adminData.token}`,
        },
    });
}
  • 后端修改为接收请求体参数:
    先创建请求DTO类:
public class CheckInRequest {
    private Long gymId;
    private String email;
    
    // 构造函数、getter和setter
}

再修改控制器方法:

@PostMapping({"/member/checkIn"})
public UserGymVisit checkInUserToGym(@RequestBody CheckInRequest request) throws RecordNotFoundException, InvalidOperationException, BadServerException {
    return adminService.checkInUsers(request.getGymId(), request.getEmail());
}

2. 移除前端无效的CORS请求头

Access-Control-Allow-Origin和Access-Control-Allow-Headers是后端返回给前端的响应头,不需要前端在请求中添加,这些请求头对跨域解决没有任何帮助,直接去掉即可。

3. 集成Spring Security时需额外配置CORS

如果项目使用了Spring Security,仅在控制器添加@CrossOrigin可能不生效,需要在Security配置中明确允许CORS:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.cors(cors -> cors.configurationSource(corsConfigurationSource()))
            // 其他Security配置...
        return http.build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of("*")); // 生产环境建议指定具体域名
        configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
        configuration.setAllowedHeaders(List.of("*"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

内容的提问来源于stack exchange,提问作者adesh landge

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 19:09:55