사실 팀프로젝트 하면서도 CORS ERROR를 겪어 보지 않았었다.
면접 단골 문제로 나온다고 해서 슬쩍 알아봤었는데 잘 와닿지는 않았다.
그리고 이번에 고생을 하며 아주 제대로 알게 되었다.. ^^
CORS 란?
Cross Origin Resource Sharing
교차 출처 리소스 공유, 교차 출처 자원 공유는 웹 페이지 상의 제한된 리소스를 최초 자원이 서비스된 도메인 밖의 다른 도메인으로부터 요청할 수 있게 허용하는 구조이다. -위키백과
역시나 뭔 소린지 모르겠다.
이걸 이해하기 위해서는 우선,
Cross-Origin과 Same-Origin 의 차이에 대해서 알아야 한다.
- SOP와 CORS
외부 정보에 접근하는 데에 있어서, 웹에는 크게 두가지 정책이 있다.
Same Origin Policy와 Cross Origin Resource Sharing 정책. 이 그 두가지이다.
먼저 SOP(Same Origin Policy)는 말 그대로 '같은 출처에서만' 정책이다. 다른 출처는 안 된다는 것.
같은 출처에서만 리소스 공유가 가능하다는 정책이다.
흔한 예시로 프론트엔드에서 백엔드로 자료를 요청한다고 해보자.
프론트 서버의 주소가 localhost:3000 이고 백엔드 서버의 주소가 localhost:8000 이라면, 결국 다른 출처에 리소스를 요청하는 것이다.
즉 SOP 정책에 따라서 CORS에러가 발생하게 되는 것.
어디까지를 같은 출처로 보는지는 Protocol, Host, Port 이 세가지에 따라 결정된다.
아래 그림에서와 같이 세가지 모두가 일치할 경우에 같은 출처로 보고 SOP 정책에 합당한 요청이 된다.
여기서 새롭게 알게된 사실은 이 출처를 비교해서 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