[LG CNS AM Inspire Camp 1기] SpringBoot (8) - CORS 해결하기

정성엽·2025년 2월 7일
1

LG CNS AM Inspire 1기

목록 보기
42/53

INTRO

이번 포스팅에서는 CORS 에러를 정리해보려고 한다.

사실 프론트엔드 서버에서 백엔드 서버로 Request를 보낼 때 마주하는 가장 흔한 에러가 바로 CORS 에러이다.

이전에 Naver Map API를 사용하여 프론트엔드 개발을 하면서 CORS 에러를 마주했었고, 이를 프록시 서버로 해결했으나 이번에는 백엔드에서는 어떻게 처리하는지 살펴볼 예정이다 👀


1. CORS란?

CORS(Cross-Origin Resource Sharing)는 보안상의 이유로 브라우저가 다른 출처(origin)의 리소스를 요청할 때 적용되는 보안 정책이다.

기본적으로 브라우저는 동일 출처 정책(Same-Origin Policy, SOP)에 따라 출처가 다른 리소스를 요청하는 것을 제한한다.

하지만 웹 애플리케이션에서 API를 호출할 때, 다른 출처의 서버로 요청해야 하는 경우가 많다.

이를 해결하기 위해 등장한 개념이 바로 CORS이다.

CORS를 이해하기위해 필요한 개념을 정리해보자

Same-Origin Policy

  • 동일한 출처에서만 요청을 허용하는 보안 정책

Preflight Request

  • 브라우저가 실제 요청 전에 OPTIONS 메서드를 이용해 서버에 미리 요청을 보내 허용 여부를 확인하는 과정

CORS Headers

  • 서버가 응답에 추가하는 헤더로, 특정 도메인에서의 요청을 허용할지 결정

우선 간단하게 읽고 넘어가자

💡 CORS 에러 발생을 통한 이해

프론트엔드를 구축하고 API를 요청하면 다음과 같이 콘솔에서 CORS 에러를 마주칠 수 있었다.

네트워크 탭을 살펴보면 다음과 같다.

우리는 이 사진을 통해 백엔드로 데이터를 요청하고 Response를 정상적으로 받아오고 있음을 확인할 수 있다.

하지만, 데이터를 사용할 수 없는 상황이다.

왜냐하면, 브라우저에서 소스의 기원이 다를 경우 데이터를 활용하는 것을 막기 때문이다.

이것이 바로 CORS 에러이다.

따라서, 실제로 데이터는 정상적으로 가져오지만 브라우저 정책에 의해 데이터 활용이 막힌다는 것을 이해하자!


2. CORS 해결 - 백엔드

이전에 첨부한 사진을 보면 Response Header에 Access-Control-Allow-Origin 내용이 없는 것을 볼 수 있다.

즉, 브라우저는 Response Header에 Access-Control-Allow-Origin이 없기 때문에 소스의 기원이 다르다고 판단하여 데이터 활용을 막는다.

따라서, 백엔드에서는 요청이 들어오면 Access-Control-Allow-Origin 헤더를 추가하여 Response를 보내주면 된다.

이렇게 헤더를 추가하여 보내주는 방법은 크게 2가지가 있다.

💡 @CrossOrigin 어노테이션 사용

Spring Boot에서는 CORS를 설정하는 여러 가지 방법이 있다.

가장 간단한 방법은 @CrossOrigin 어노테이션을 사용하는 것이다.

예제 코드를 살펴보자

Sample Code

@CrossOrigin(origins = "http://localhost:5173")
@RestController
@RequestMapping("/api")
public class RestApiBoardController {
	...
}

이처럼 컨트롤러에 @CrossOrigin 어노테이션을 추가하여 특정 URL로 들어오는 Request를 허용하는 것이다.

하지만 이렇게 개별 컨트롤러에 적용하는 방법보다는 글로벌 설정을 적용하는 것이 효율적일 수 있다.

💡 Global CORS 설정 (WebMvcConfigurer 사용)

이전에 Interceptor를 설명할 때, WebMvcConfigurer 인터페이스는 SpringBoot의 default 세팅을 커스터마이징할 수 있는 인터페이스라고 설명한 적이 있다.

이전에는 인터셉터 관련 설정을 변경했고, 이번에는 CORS 관련 설정을 추가해보려고 한다.

Sample Code

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggerInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/css/**")
                .excludePathPatterns("/js/**")
                .excludePathPatterns("/images/**");
    }

    @Override
    public void addCorsMappings(CorsRegistry registry){
        registry
                .addMapping("/api/**")
                .allowedOrigins("http://localhost:5173")
                .allowedMethods("GET");
    }
}

이처럼 addCorsMappings(CorsRegistry registry) 메서드를 오버라이딩하여 세팅하면 된다.

registry에 허용할 Origins과 Method 방식을 세팅할 수 있다!


3. CORS 해결 - 프론트엔드

프론트엔드에서도 CORS 문제를 해결할 수 있다.

만약, 백엔드 서버에서 CORS 세팅을 해줄 수 있는 여건이 안되는 경우 (ex. Naver Map API 사용)에는 어쩔수 없이 프론트엔드에서 세팅을 수행해야 한다.

프론트엔드에서는 vite를 사용하여 프로젝트를 세팅했을 경우
vite.config.js 에서 프록시를 설정해주면 된다.

Sample Code

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
        secure: false
      }
    }
  }
});

이처럼 프록시 서버를 세팅해주면 (클라이언트 → 프록시 서버 → 백엔드 서버) 로 Request가 나가게 된다.

마찬가지로 Response도 (백엔드 서버 → 프록시 서버 → 클라이언트) 의 과정으로 들어오게 된다.

이렇게 되면 브라우저는 데이터의 Origin을 우리가 세팅한 프록시 서버로 이해하게 된다.

결과적으로 같은 출처(Origin)인 것처럼 보이게 만들어 CORS 문제를 우회하는 방식으로 해결할 수 있는 것이다!


OUTRO

이번 포스팅에서는 CORS 에러의 개념과 원인, 그리고 이를 해결하는 방법을 정리해보았다.

백엔드에서 CORS 정책을 올바르게 설정하는 것이 가장 확실한 방법이지만, 경우에 따라 프록시를 활용하는 방법도 고려할 수 있다.

이번 포스팅이 CORS 문제를 해결하는 데 도움이 될 수 있으면 좋겠다 👊

profile
코린이

0개의 댓글

관련 채용 정보