본문 바로가기

JavaScript/React

[React] CORS 오류 해결하기

728x90
반응형

React를 접하면 흔히 나오는 장면인 CORS 오류.. 누구나 보게 되는 장면이라 생각된다.

 

 

 

클라이언트인 React는 기본적으로 locathost:3000이고 보통 서버단은 localhost:8080으로 사용하게 될 것이다.

이렇게 Origin이 다르다 보니 해당 오류가 발생하는 것이다. 해당 문제에 대해 좀 더 알아보자.

 

 

 

1. SOP 란?

우선 CORS를 알기전 SOP 개념에 대해 알아야 한다.

SOP(Same Origin Policy) 이란 '동일 출처 정책' 이라고 하며, 다른 Origin에서 리소스를 가지고 오거나 보내는 등 상호작용 하는 것을 제한하는 보안 방식이다.

즉, 웹 브라우저에서 보안을 강화하기 위해 동일한 Origin에서만 리소스를 주고받도록 하는 정책이다.

 

여기서 Origin(출처) 에 대해서도 자세히 알아보자

 

Origin은 위 그림에 나와있듯이 특정 도메인 위치를 찾아가기 위해 필요한 가장 기본적인 것들을 합쳐놓은 것이다. 여기서 프로토콜, 호스트, 포트 번호가 다르면 SOP을 위반하여 CORS 문제가 발생하는 것이다.

 

728x90

 

 

 

 

 

 

 

 

2. CORS 란?

CORS(Cross-Origin Resource Sharing) 란 '교차 출처 리소스 공유' 라고 하며, 앞서 말한 SOP에 의해 다른 Origin에서 리소스를 받아오는 것이 제한되기에 이러한 문제를 해결하기 위해 나온 정책이 바로 CORS이다.

즉, 도메인이 다른 서버끼리 리소스를 주고받을 때 보안을 위해 Origin을 설정하는 정책이라 생각하면 된다.

 

이제 여러 방법들을 통해 CORS 문제를 해결해 보자

 

반응형

 

 

 

 

 

 

 

 

 

 

 

3. CORS 해결

- Spring Security 사용

 

Spring + React를 사용한다는 가정하에 진행하면 된다. 

 

먼저 build.gradle에 아래의 의존성을 추가해 준다.

// spring-security dependency
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'

 

 

 

그리고 SecurityConfig 파일과 CorsConfig 파일을 작성해 준다.

@RequiredArgsConstructor
@Configuration
@EnableWebSecurity 
public class SecurityConfig {

    private final CorsConfig corsConfig;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                .cors()
                .configurationSource(corsConfig.corsConfigurationSource())
                .and()
                .formLogin().disable()
                .csrf().disable() 
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeHttpRequests()
                .requestMatchers("/**").permitAll()
                .anyRequest().authenticated();

        return httpSecurity.build();
    }

}

 

@Configuration
public class CorsConfig {

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();

        configuration.setAllowedOrigins(List.of("http://localhost:3000"));
        configuration.setAllowedMethods(List.of("*"));
        configuration.setAllowedHeaders(List.of("*"));
        configuration.setAllowCredentials(true); 

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

        return source;
    }
}

 

CorsConfig에서 React의 Origin인 localhost:3000을 넣어주고 작성해 준다. 그리고 SecurityConfig에서 작성한 CorsConfig를 추가해 주면 CORS 오류를 해결할 수 있다.

 

 

 

 

 

- Proxy 사용

 

React 상에서 진행을 해주면 된다. 

 

우선 http-proxy-middleware를 설치한다.

npm install http-proxy-middleware --save

 

 

설치 후 React 최상위 폴더에서 아래와 같은 내용으로 작성하여 setupProxy 파일을 만들어준다.

target 부분에 서버 도메인을 작성해주고 changeOrigin을 true 값을 주면 된다.

// setupProxy.ts
const { createProxyMiddleware } = require("http-proxy-middleware");

module.exports = (app) => {
    app.use(
        "/api",
        createProxyMiddleware({
            target: "http://localhost:8080",
            changeOrigin: true
        })
    );
};

 

 

 

 

그 후 사용하고자 하는 곳에 setupProxy에서 설정한 "/api" 를 넣어준다. 나는 axios를 사용하기에 아래와 같이 작성하였다.

...

useEffect(() => {
    const getListData:object = {
        pageNo: pageNo,
        institutionNo: institutionNo,
        searchCategory: searchCategory,
        searchText: searchText,
    }
    const boardList = async () => {
        await axios({
            method: "POST",
            url: '/api/board/boardList', // 맨앞에 설정한 proxy의 '/api' 넣어주기
            data: JSON.stringify(getListData),
            headers: {'Content-type': 'application/json'}
        }).then((res):void => {
            setBoardList(res.data.data.boardList);
            setTotalPage(res.data.data.totalPage);
        }).catch((err):void => {
            console.log(err.message);
        });
    }
    setTimeout(() => {boardList().then();}, 0);
}, [pageNo, institutionNo, searchCategory, isSearchActive])
    
...

 

만약 axios를 사용하면서 baseURL을 설정하였다면 설정한 baseURL을 제거해 주어야지 정상적으로 동작할 것이다.

 

위 방법은 자신이 사용하는 서버뿐만이 아닌 다른 곳의 API를 사용할 때도 사용해 주면 좋다. 보다 유연하고 다양하게 대처할 수 있기에 위 방법을 추천하고 선호한다.

 

 

 

 

 

 

 

728x90
반응형