Spring Boot에서 CORS 오류 해결 방법: 원인부터 설정까지 완벽 정리

Spring Boot에서 CORS 오류 해결 방법: 원인부터 설정까지 완벽 정리 이미지 1

안녕하세요. IT 기술 블로거입니다.

React나 Vue 같은 프론트엔드와 Spring Boot 백엔드를 연결해 본 적이 있다면, 누구나 한 번쯤은 콘솔창을 가득 채우는 빨간색 메시지를 본 적이 있을 것입니다.

“Access to fetch at ‘…’ from origin ‘…’ has been blocked by CORS policy…”

바로 악명 높은 CORS(Cross-Origin Resource Sharing) 에러입니다. 분명 서버는 잘 돌아가고 Postman으로 쏠 때는 응답이 오는데, 왜 브라우저에서만 안 되는 걸까요? 오늘은 이 에러의 정체와 Spring Boot에서 깔끔하게 해결하는 3가지 방법을 정리해 드립니다.


1. CORS란 무엇이고 왜 발생하는가?

CORS는 “교차 출처 리소스 공유”를 의미합니다. 브라우저의 보안 정책 중 하나인 SOP(Same-Origin Policy, 동일 출처 정책) 때문입니다.

출처(Origin)란?

Protocol(http/https) + Host(domain) + Port(80/8080) 3가지가 모두 같아야 동일 출처로 인정합니다.
– 프론트엔드: http://localhost:3000
– 백엔드: http://localhost:8080

포트 번호가 다르기 때문에 브라우저는 이를 ‘다른 출처’로 간주하고 보안상의 이유로 차단합니다. 즉, 서버가 차단하는 게 아니라 브라우저가 서버로부터 받은 응답을 가로채서 에러를 내뱉는 것입니다.


2. Spring Boot 해결 방법 1: @CrossOrigin 사용

특정 컨트롤러나 메서드에만 적용하고 싶을 때 사용하는 가장 간단한 방법입니다.

@RestController
@RequestMapping("/api/members")
@CrossOrigin(origins = "http://localhost:3000") // 특정 도메인 허용
public class MemberController {

    @GetMapping("/{id}")
    public Member getMember(@PathVariable Long id) {
        return memberService.findById(id);
    }
}
  • 장점: 매우 쉽고 직관적입니다.
  • 단점: 컨트롤러가 많아지면 모든 곳에 붙여야 하므로 중복이 발생하고 관리가 어렵습니다.

3. 해결 방법 2: WebMvcConfigurer 글로벌 설정 (권장)

프로젝트 전체에 일괄적으로 적용하고 싶을 때 사용하는 실무 권장 방식입니다.

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 모든 경로에 대해
                .allowedOrigins("http://localhost:3000", "https://my-domain.com") // 허용할 도메인
                .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS") // 허용할 HTTP 메서드
                .allowedHeaders("*") // 모든 헤더 허용
                .allowCredentials(true) // 쿠키/인증 정보 포함 허용 여부
                .maxAge(3600); // 프리플라이트(Preflight) 요청 캐싱 시간 (초)
    }
}

이 설정 하나면 프로젝트 내의 모든 API에 대해 지정한 도메인에서의 접근이 허용됩니다.


4. 해결 방법 3: Spring Security 설정

만약 프로젝트에 Spring Security를 적용 중이라면, 위의 WebMvcConfigurer 설정만으로는 부족할 수 있습니다. Security 필터 체인에서 먼저 차단되기 때문입니다.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .cors(cors -> cors.configurationSource(corsConfigurationSource()))
            // ... 기타 설정
            .csrf(csrf -> csrf.disable());
        return http.build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOrigin("http://localhost:3000");
        configuration.addAllowedMethod("*");
        configuration.addAllowedHeader("*");
        configuration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

Spring Boot에서 CORS 오류 해결 방법: 원인부터 설정까지 완벽 정리 이미지 2

결론

CORS 오류는 서버의 잘못이 아니라 브라우저의 보안 정책을 준수하기 위한 일종의 “신고 과정”입니다.

  1. 간단한 테스트는 @CrossOrigin으로,
  2. 실무 프로젝트는 WebMvcConfigurer를 통한 글로벌 설정으로,
  3. 보안이 적용된 프로젝트는 SecurityConfig에서 해결하세요.

중요한 것은 보안을 위해 allowedOrigins("*")처럼 모든 도메인을 허용하기보다는, 실제 사용하는 도메인만 명시하는 것이 좋습니다. 이 가이드가 여러분의 프론트-백엔드 협업의 첫 걸음을 가볍게 만들어 주길 바랍니다. 감사합니다!

관련 글 보기