개발

[React.js, 스프링부트, AWS로 배우는 웹 개발] 3장 - CORS

jih0ssang 2024. 7. 23. 15:47

참고 블로그: https://evan-moon.github.io/2020/05/21/about-cors/#cors%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%9E%91%ED%95%98%EB%82%98%EC%9A%94

 

CORS ( Cross-Origin Resource Sharing 크로스-오리진 리소스 셰어링 )

애플리케이션을 통합하면서 우리는 CORS 문제를 맞닥뜨리게 된다.

이 문제는 백엔드에서 해결해야 한다.

 

componentDidMount

Todo 아이템을 불러오는 부분이다.

우리가 http://localhost:3000 접속하면 Todo 아이템이 리스트에 보여야 한다.

 

렌더링이란?
리액트는 브라우저에 보이는 HTML DOM 트리의 다른 버전인 ReactDOM(Virtual DOM)을 갖고 있다.
어떤 이유로 컴포넌트의 상태가 변하면 ReactDOM은 이를 감지하고 변경된 부분의 HTML을 바꿔준다.
HTML이 업데이트되면 우리는 변경된 결과를 눈으로 확인할 수 있다.
이를 렌더링이라고 한다.

 

렌더링이 맨 처음 일어나는 순간, 즉 ReactDOM 트리가 존재하지 않는 상태에서 리액트가 처음으로 각 컴포넌트의 render() 함수를 콜해

자신의 DOM 트리를 구성하는 과정을 마운팅이라고 한다.

마운팅 과정에서 생성자와 render() 함수를 부르는데 마운팅을 마친 후 바로 componentDidMount 함수를 부른다.

우리는 컴포넌트가 렌더링되자마자 API 콜을 하고 그 결과를 리스트로 보여주려고 componentDidMount 함수에 백엔드 API 콜 부분을 구현해야 한다.

 

왜 생성자에서 API 콜을 안하고 따로 함수를 쓰는가? 생성자에서 리스트를 초기화하는 것이 로직상 맞지 않은가?

그렇다. 하지만 마운팅이 다 되지 않은 상태라는 것은 컴포넌트의 properties가 아직 준비되지 않은 상태라는 뜻이다.

필요한 모든 Properties 의 존재 여부를 모르는 상태에서 API 콜을 해 상태를 변경하면 프로그램이 예기치 못한 방향으로 동작할 수 있다.

 

[App 컴포넌트에 componentDidMount 추가]

componentDidMoun() {
  const requestOptions = {
    method: "GET",
    headers: { "Content-Type": "application/json" },
  };
  
  fetch("http://localhost:8080/todo", requestOptions)
    .then((response) => response.json())
    .then(
      (response) => {
        this.setState({
          item: response.data,
        });
     },
     (error) => {
       this.setState({
         error,
       });
     }
  );
 }
  • localhost:3000 접속하여 개발자 툴의 콘솔창을 켜보면 에러를 확인할 수 있다.

 

[CORS 에러]

Access to fetch at 'http://localhost:8080/todo' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
App.js:24 GET 'http://localhost:8080/todo' net::ERR_FAILED

이는 보안을 위한 CORS 헤더 Policy를 위반했기 때문이다.

 

 

CORS (Cross-Origin Resource Sharing)

  • 이러한 출처를 비교하는 로직이 서버가 아니라 브라우저에 구현된 스펙이다. Cross-Origin(출처 변경)을 차단한다.
  • 서버는 CORS를 위반해도 정상 응답하고, 브라우저는 응답 파기 한다.

 

 

1. 브라우저는 요청 헤더에 Origin 필드 에 요청을 보내는 Origin(출처)를 함께 담아 보낸다.

Origin: https://website.com

브라우저는 서버에게 리소스를 받아오는 예비 요청을 보낸다.

 

2. 서버가 해당 요청에 대한 응답 시, 응답 헤더의 Access-Control-Allow-Origin 값에 "이 리소스를 접근하는 것이 허용된 출처" 제공

Access-Control-Allow-Origin: "http://content.com"

서버는 이 예비 요청에 대한 응답으로 현재 자신이 어떤 것들을 허용하고, 어떤 것들을 금지하고 있는지에 대한 정보를 응답 헤더에 담아서 브라우저에게 다시 보내게 된다.

 

3. 응답을 받은 브라우저는 자신이 보냈던 요청의 Origin과  서버가 보내준 응답의 Access-Control-Allow-Origin을 비교한 후 이 응답이 유효한 응답인지 결정한다.

이 단계가 Cross-Origin 거부를 하는 단계이다.

현재 Origin과 Access-Control-Allow-Origin이 다른 부분은 브라우저는 Cross-Origin 거부한다.

 

 

 

백엔드 서버(스프링 부트) CORS 설정

  • 위의 코드처럼 CORS  설정에서 https://website.com  에서 오는 요청 허용
  • CORS 설정한 경우, 브라우저가 받은 Access-Control-Allow-Origin에 https://website.com 이 포함되어 Origin과 동일하므로 Cross-Origin 문제가 생기지 않는다.

 

S3 (사진, 파일 저장용) CORS 설정

  • 프론트엔드에 담긴 사진, 파일, 영상이 담긴 content S3 에도 CORS 설정한다.