본문 바로가기

Frontend Study - 2/CORS

CORS ERROR란? CORS 에러 개념 및 해결.

사실 팀프로젝트 하면서도 CORS ERROR를 겪어 보지 않았었다.

면접 단골 문제로 나온다고 해서 슬쩍 알아봤었는데 잘 와닿지는 않았다.

 

그리고 이번에 고생을 하며 아주 제대로 알게 되었다.. ^^

 

CORS 란?

 

Cross Origin Resource Sharing

교차 출처 리소스 공유, 교차 출처 자원 공유는 웹 페이지 상의 제한된 리소스를 최초 자원이 서비스된 도메인 밖의 다른 도메인으로부터 요청할 수 있게 허용하는 구조이다. -위키백과

 

역시나 뭔 소린지 모르겠다.  

 

이걸 이해하기 위해서는 우선,

Cross-Origin과 Same-Origin 의 차이에 대해서 알아야 한다.

 

- SOP와 CORS

 

외부 정보에 접근하는 데에 있어서, 웹에는 크게 두가지 정책이 있다. 

Same Origin PolicyCross Origin Resource Sharing 정책. 이 그 두가지이다.

 

먼저 SOP(Same Origin Policy)는 말 그대로 '같은 출처에서만' 정책이다. 다른 출처는 안 된다는 것. 

같은 출처에서만 리소스 공유가 가능하다는 정책이다.

 

흔한 예시로 프론트엔드에서 백엔드로 자료를 요청한다고 해보자.

프론트 서버의 주소가 localhost:3000 이고 백엔드 서버의 주소가 localhost:8000 이라면, 결국 다른 출처에 리소스를 요청하는 것이다.

즉 SOP 정책에 따라서 CORS에러가 발생하게 되는 것.  

 

어디까지를 같은 출처로 보는지는 Protocol, Host, Port 이 세가지에 따라 결정된다.

아래 그림에서와 같이 세가지 모두가 일치할 경우에 같은 출처로 보고 SOP 정책에 합당한 요청이 된다.

 

https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-CORS-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-%F0%9F%91%8F

 

 

여기서 새롭게 알게된 사실은 이 출처를 비교해서 CORS 에러를 날리는 로직이 브라우저에서 구현된다는 점이었다!

 

서버에서 요청을 받은 뒤, ok 하고 200과 함께 데이터를 응답한다고 해도,

브라우저에서 중간에 그 응답을 처리하지 않고 에러메시지를 띄우는 것.

 

 

이제 CORS에러가 나는 원인에 대해서는 알게 되었다.

결국 에러메시지가 하는 얘기는, 네가 한 요청이 다른 출처로 한 요청이니까 응답을 보내줄 수 없다는 얘기이다. 

 

 

- CORS기본 과정

 

 

개발자도구 - 네트워크로 들어가 요소를 클릭해 Headers를 확인해보면,

클라이언트는 요청시 위와 같이 request 부분에 origin을 넣어 요청하고,

서버는 아래와 같이 헤더에 Access-Control-Allow-Origin을 넣어 응답한다.

 

 

 

 

브라우저는 이 둘이 같은지 확인하고, 

다르다면 CORS 에러를 내는 것이다.

 

 

 

- 그래서 해결방안

 

이곳 저곳에서 cors 관련 자료도 많고 해결 방법도 바로 나왔기 때문에 쉽게 해결할 수 있을 것이라 생각했지만,

의외로 해결이 잘 되지 않았었다...후..진짜ㅠ

 

첫번째 시도했던 방법은,

 

1. axios의 widhCredentials 옵션 부분을 전역 설정으로 처리하기. 

axios.defaults.withCredentials = true;

 

axios로 통신을 진행했고, 전역으로 설정을 해보았지만 여전히 cors에러가 났었다.

 

 

2. 두번째 방법은.

axios로 요청하는 주소값 앞에 "proxy.cors.sh/" 를 붙여서 요청 하는 것이었다. 

"https://proxy.cors.sh/myportfolio3039.s3.ap-northeast-2blahblah.json";

되지 않았다.

 

 

3. 세번째 방법! 이 방법으로 나는 해결 할 수 있었다.

 

CORS에러는 Proxy역할을 해주는 중간 서버를 만들어 해결할 수도 있지만 번거로운 접근법이었다.

이 때 Webpack에서 간단하게 Proxy기능을 지원해준다는 것을 알게 되었다. 

 

//package.json

{

  "proxy": "https://snowdeer.com"

}

 

package.json에서 위와 같이 실제 접속하려고 하는 서버의 루트 URL을 "proxy" : "xx" 로 처리해 준다. (루트 URL만!)

그리고

기존의 통신을 요청했던 URL값을 루트를 제외한 그 뒤의 경로값으로 수정해 주었다.

 

const App = () => {
  const URL = '/menu/getMenuList.do?type=2'
}

 

그랬더니 해결이 되었다.

 

사실 가장 근본적인 해결책은 서버쪽에서 Access-Control-Allow-Origin을 세팅해주는 것이다. 

res.setHeader('Access-Control-Allow-origin', '*');
//or
res.setHeader('Access-Control-Allow-origin', 'https://goddemi.tistory.com');

res.setHeader('Access-Control-Allow-Credentials', 'true'); // 쿠키 주고받기 허용

 

 

참고사이트

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS/Errors

https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-CORS-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-%F0%9F%91%8F