동일한 출처 예시 사진: https://ko.wikipedia.org/wiki/%EB%8F%99%EC%9D%BC-%EC%B6%9C%EC%B2%98_%EC%A0%95%EC%B1%85
이러한 동일 출처 정책이 있기 때문에 브라우저가 다른 출처에서 리소스를 받아오는 것을 제한한다.
하지만 개발을 하다보면 기능을 위해 다른 출처 간의 상호작용을 해야하는 케이스도 있고, 네이버 지도 API같이 다른 회사의 서버 API를 이용해야 하는 상황도 존재한다.
따라서 이런 예외 사항을 두기 위해 CORS 정책을 허용하는 리소스에 한해서 다른 출처라도 받아들인다는 뜻이다.
즉, CORS는 다른 출처의 리소스를 얻기 위한 해결방안이다.
CORS 동작방식
CORS 접근 제어 시나리오 (교차 출처 리소스 공유가 동작하는 방식)에는 크게 세가지가 있다.
1. 프리플라이트 요청 (Preflight Request)
실제 요청을 보내기 전에 예비 요청을 보내 해당 출처 리소스에 접근 권한이 있는지부터 확인하는 방식
사진 출처: https://developer.mozilla.org/ko/docs/Web/HTTP/CORS#access-control-expose-headers
위의 사진과 같이 OPTIONS method를 통해서 Main request 전에 Preflight request를 보내고, Response 헤더의 Access-Control-Allow-Origin으로 요청을 보낸 출처가 돌아오면 Main request를 보낸다. 만약 요청을 보낸 출처가 접근 권한이 없다면 CORS 에러를 띄우고, 요청은 전달되지 않는다.
응답을 좀 더 자세히 보자면
Access-Control-Allow-Origin: http://foo.example - 응답을 보내준 다른 출처
Access-Control-Allow-Methods: POST, GET, OPTIONS - 서버의 응답. POST와 GET이 리소스를 쿼리하는데 유용한 메서드라고 가르쳐줌.
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type - "X-PINGOTHER, Content-Type"으로 전송하여 실제 요청에 헤더를 사용할 수 있음을 확인
Access-Control-Max-Age: 86400 - 응답을 캐시할 수 있는 시간(초)을 제공. *86400(24시간)
2. 단순 요청 (Simple Requests)
사진 출처 http://man.hubwiz.com/docset/HTTP.docset/Contents/Resources/Documents/developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS.html
단순요청은 Preflight Request와 다르게 요청을 보내면서 즉시 Cross Origin인지 확인하는데 다음 조건을 모두 충족해야한다.
위 사이트 들어가서 데모 서버 활성화 버튼 클릭한다. 시간제한이 있어서 일시적인 해결 방법이다.
const url = 'https://google.com' // 이 부분을 이용하는 서버 URL로 변경
fetch(`https://cors-anywhere.herokuapp.com/${url}`)
.then((response) => response.text())
.then((data) => console.log(data));
2. cors proxy app 프록시 서버
axios 라이브러리 설치가 필요하다.
<script src='https://cdnjs.cloudflare.com/ajax/libs/axios/1.1.3/axios.min.js'></script>
<script>
axios({
url: 'https://cors-proxy.org/api/',
method: 'get',
headers: {
'cors-proxy-url' : 'https://google.com/' // 이 부분을 이용하는 서버 URL로 변경
},
}).then((res) => {
console.log(res.data);
})
</script>
const url = 'https://google.com' // 이 부분을 이용하는 서버 URL로 변경
fetch(`https://proxy.cors.sh/${url}`)
.then((response) => response.text())
.then((data) => console.log(data));