Back-end/Spring

[Spring] CORS이 무엇이며 Spring Boot에서 해결 하는 방법

랑 이 2025. 4. 10. 15:45
반응형

CORS 에러

백엔드 개발을 끝내고 프론트에서 서버에 요청하여 데이터를 가져올 때 자주 생기는 오류인데요 

오류 내용을 보면 다음과 같습니다

'http://localhost:3000'에서 XMLHttpRequest를 통해 'http://localhost:8080/api/posts'로 요청을 보냈지만, CORS 정책에 의해 차단되었습니다.그 이유는, 응답에 'Access-Control-Allow-Origin' 헤더가 포함되어 있지 않기 때문입니다.

 

React(3000번 포트)에서 Spring 서버(8080)로 요청을 보냈지만 서로 다른 Origin이기 때문에 브라우저는 동일 출처 정책(SOP)에 따라 응답 접근을 차단합니다

 

이때 서버(Spring)는 응답을 보냈더라도 응답 헤더에 Access-Control-Allow-Origin이 명시되어 있지 않으면
브라우저는 보안상 해당 응답을 신뢰할 수 없기 때문에 CORS 에러를 발생시키며 차단합니다

 

브라우저는 기본적으로 SOP(동일 출처 정책)을 따르지만 다른 출처(Origin)에서 요청을 허용하기 위해 서버에서 CORS로 설정하여 다른 출처에서도 요청을 허용하여 CORS 에러를 해결할 수 있습니다 

Origin,SOP,CORS 이란?

1. Origin

출처(Origin): Protocol + Host + Port를 합친 URL

  • Protocol: http,https
  • Host: 사이트 도메인
  • Port: 포트 번호 

2. SOP (Same-Origin Policy)

웹 브라우저의 보안 정책으로 같은 출처(Origin)에서 온 리소스만 접근을 허용하는 동일 출처 정책입니다

다른 출처(origin)에서리소스는 접근을 허용하지 않아 사용할 수 없으며 에러를 발생하게 됩니다

여기서 발생되는 에러가 CORS 에러입니다

 

같은 출처는 어떻게 구분할까?

Protocol,Host,Port 세가지 요소가 모두 동일하며 같은 출처로 판단하고 있다

하나라도 다르면 브라우저는 다른 출처로 판단한다

3. CORS (Cross-Origin Resource Sharing)

다른 출처의 리소스 공유에 대한 허용/비허용 정책으로 교차 출처 리소스 공유 정책입니다

 

기본 브라우저에서는 SOP 정책으로 다른 Origin의 요청을 막기 때문에 서버와 통신하는 과정에서 에러가 발생되는데

서버에서 CORS 헤더로 특정 Origin은 허용하는 설정을 하여 에러를 해결할 수 있습니다

 

CORS 에러를 해결하기 위해서는 서버에서 Access-Control-Allow-Origin 헤더에 허용할 출처를 작성하여 응답하도록 설정하는 것입니다 Spring Boot에서 CORS 에러를 해결하는 방법에 대해서 설명합니다

 

Spring Boot 에서 CORS 에러 해결하는 방법

1. 특정 컨트롤러에서 허용 (@CrossOrigin )

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:3000")
public class MyController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from Spring Boot 3!";
    }
}

특정한 컨트롤러만 허용이 필요한 경우 유용하게 사용할 수 있을 것 같습니다

컨트롤러 내부에 있는 메서드에도 설정이 가능합니다

 

2. 전역으로 설정 (WebMvcConfigurer)

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")                                      // 모든 API 경로
                .allowedOrigins("http://localhost:3000")                // 허용할 출처 (URL)
                .allowedMethods("GET", "POST", "PUT","PATCH", "DELETE") // HTTP 메서드 허용
                .allowedHeaders("*")                                    // 모든 헤더 허용
                .allowCredentials(true);                                // 쿠키 인증 요청 허용 
    }
}

WebConfig 클래스를 생성하고 WebMvcConfigurer 인터페이스를 상속받아 사용합니다

 

@Configuration 

- 해당 클래스가 Spring 설정 클래스임을 명시

- 내부에 있는 설정이 Spring Boot 애플리케이션에 적용

 

implements WebMvcConfigurer

WebMvcConfigurer를 상속받아 addCorsMappings 메서드를 오버라이딩 하여 CORS 설정을 전역적으로 커스터마이징

 

addMapping("/**")

- /**는 모든 경로(API)에 대하여 CORS 설정을 적용

 

.allowedOrigins("http://loclhost:3000")

- 해당 Origin(출처)에서 온 요청을 허용

- 리액트 프로젝트를 테스트 환경으로 사용하여 React 기본 서버(3000 port)를 지정

 

.allowedMethods("GET", "POST", "PUT","PATCH", "DELETE")

- 허용할 HTTP 메서드를 지정

- 여기서는 REST API의 기본 HTTP 메서드를 지정하여 허용함

 

.allowedHeaders("*")

- 요청 시 어떤 HTTP 헤더를 허용할지 지정

- "*" 으로 모든 헤더를 허용

 

.allowCredentials(true)

- 인증 정보를 포함한 요청을 허용할지 여부 

- 쿠키,세션 등

- true로 설정하면 allowedOrigins("*")와 같이 사용불가 (보안 문제)

CORS 테스트해보기

먼저 서버에 요청하고 응답을 받을 환경을 만들기 위해 테스트로 진행할 React 프로젝트를 생성해 줍니다

npx create-react-app my-app
cd my-app
npm start

코드를 순서대로 터미널에 작성하여 리액트 프로젝트를 생성합니다

 

생성된 App.js에 작성합니다

import logo from './logo.svg';
import './App.css';
import { useEffect,useState } from 'react';
import axios from "axios";

function App() {
    const [items, setItems] = useState([]);
  
    useEffect(() => {
      axios.get("http://localhost:8080/api/posts") // 서버 주소에 맞게 수정
        .then(res => {
            setItems(res.data);
        })
        .catch(err => {
            console.error("Error fetching data:",err)
        })
    }, []);
  
    return (
      <div>
        <h1>서버에서 받은 데이터</h1>
        {items.map(item => 
            <div>
                <h2>제목: {item.title}</h2>
                <p>내용: {item.content}</p>
                <span>작성자: {item.name}</span>
            </div>
        )}
      </div>
    );
  }
  

export default App;

이전에 만들었던 Spring 백엔드 서버에 데이터를 요청하여 값을 출력하는 간단한 웹 페이지를 구성했습니다

 

백엔드 서버를 실행 후 게시글을 작성하고 리액트에서 정상적으로 출력되는지 확인합니다

Swagger UI에서 게시글 작성을 진행합니다

정상적으로 데이터를 가져와 출력하는 걸 볼 수 있습니다

 

반응형