먼저, 이름의 의미부터 알아보자.
뜻을 잘 조합하여 간단명료하게 만들어보자.
출처가 서로 다른 곳에서 시작된 자원들이 공유하는 것!
프로그래밍적으로 본다면 뜻을 알 수가 없다. 현실세계에서 비유하자면 출처가 서로 다른 곳에서 시작된 자원들이라고 하면 서로 다른 곳에서 만들어진 자원은 나무, 물, 금속, 광물등이 있다. 그리고 그것을 공유하는 것이라고 하면 광물을 사용하는 곳에서 물도 취급하게 하고, 나무를 사용하는 곳에 금속도 취급하게 하는 것이다.
그러면 프로그래밍적으로 과연 어떠한 상황일 때 CORS
인 상황인지 한 번 생각만 해보자,
일단, 나는 프로젝트를 할 때, CORS라는 것을 정확히 모르고 사용했다. 그래서 다시 한 번 깨끗하게 CORS에 대해서 생각을 비우고 다시 생각해보자!
뭔가, HTTP와 HTTPS?, 아니면 기준이라고 한다면 정확히 알 수가 없는데, HTTP와 HTTPS라고 한다면 프로토콜의 차이? 라고 생각이 든다.
일단, 출처를 알아보기 전에 URL의 구조를 먼저 알아보자,
프로토콜의 HTTP는 80번, HTTPS는 443번 포트를 사용한다. 이 포트는 URL에서 생략이 가능하다.
Origin, 출처
출처(Origin)란, URL의 구조 중 Protocol
, Host
, Port
를 합친 것을 말한다.
브라우저 개발자 도구
- 콘솔
창에서 location.origin
를 실행하면 출처를 확인 할 수 있다.
연습 (나는 연습을 해야만 더욱 더 머릿속에 오래 남기 때문에 연습을 해야만 한다.)
https://github.com/kihunism/codingDic
이러한 URL이 있으면 https://
는 프로토콜, github.com
은 Host 포트번호는 443
이다.
즉, 여기까지가 출처(Origin)
이다.
백엔드(서버) 프로그래밍을 하다보면 일단 서버 응답을 먼저 구현한다. 그리고 서버가 잘 작동하는 지와 내가 구현한 응답이 잘 오는지에 대해서 포스트맨 같은 프로그램으로 테스트한다. 이 때만 해도 서버는 작동을 잘 하는 것을 보고 있다가 로컬에서 테스트를 하거나, 더 나아가 배포 단계에서 테스트를 할 때에 갑자기 has been blocked by CORS policy
라는 문구가 들어있는 오류를 자주 만나게 된다. 이 이유는 브라우저가 동일 출처 정책을 지키는 중이라 다른 출처의 자원 공유를 금지하고 있기 때문이다. 그러나 BUT, 실제로는 자주 다른 출처의 자원을 사용해야 한다. 어쩌면 무조건, 항상 사용해야 할 수도 있다.
CORS의 동작 방식은 2가지 이다. 단순요청방법, 예비요청방법이다.
Simple Request (단순 요청 방법)
단순 요청 방법은 서버에게 바로 요청을 보내는 방법이다.
요청메서드는 GET, HEAD, POST 중 하나이며, Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width를 제외한 헤더를 사용하면 안되며, Content-Type 헤더는 application/x-www-form-urlencoded, multipart/form-data, text/plain 중 하나를 사용해야 한다.
위에 설명한 조건 중 요청메서드는 지키기 쉬운 조건이지만 두번 째와 마지막 조건은 상당히 까다로운 조건으로 평가받는다. 요즘 Content-Type으로 많은 RESTful한 API들은 application/json을 사용하므로 사실상 지키기 어려운 조건으로 평가받는다.
Preflight Request (예비 요청 방법)
Preflight 요청은 서버에 예비 요청을 먼저 보내서 안전한지 판단 후 실제 요청을 보내는 방법이다.
요청메서드를 GET, POST, PUT, DELETE와 같은 자주 사용하는 메서드로 클라이언트에서 요청을 하게 되면 크롬 개발자 도구
의 Network
탭에 보면 요청이 2가지 인 것을 확인 할 수 있다. 나는 이러한 현상이 오류인 줄 알았다. 왜냐하면 내가 쿠키전송 오류에 관해서 계속 개발자도구를 열어서 확인하는 도중에 요청이 2개가 오고 메서드가 OPTION이고 응답 코드도 내가 설정한 코드가 아니길래 오류인 줄 알고 다른 사람들에게 계속 물어봤던 기억이 있다. 하지만 이러한 현상은 지극히 정상이며 CORS 정책을 지키고 있다는 것이다.
fetch(), axios()등 클라이언트에서 요청을 보내면 예비요청이 먼저 보내지고 안전한지 판단 후 다시 실제 요청을 보내는 것을 직관적으로 확인 할 수 있다.
npm i cors
모든 요청을 허용할 경우 간단하게 미들웨어를 불러와서 추가하는 것으로 해결이 된다.
server/index.js
const express = require('express')
const cors = require('cors')
const app = express()
...
const corsOption = {
origin: true,
credential: true
}
app.use(cors(corsOption)) // CORS 미들웨어 등록
여기서 매우 중요한 것은 바로 corsOption 이다.
Origin(출처)는 어떤 출처를 가능하게 하느냐 이다. true
로 설정하면 다른 출처를 허용한다는 뜻이므로 true
로 설정한다. 물론, 직접 URL을 설정할 수도 있다.
credential은 클라이언트의 요청에서 설정할 수가 있는데, 사용자 인증이 필요한 자원 공유에서 true
를 해야 한다. 기본값은 false
오늘 CORS에 대해서 블로깅을 하면서 공부를 하였는데, 개인프로젝트를 하면서 서버를 구성할 때 정확히 알고 세팅해야 하는 것이 너무나 많다는 것을 또 한 번 느낀다.
다음 프로젝트 때 정확히 알고 사용해야하며 단순히 프로젝트를 양산하는 것 보다는 내가 코드를 한 줄 치더라도 그 한 줄 짜리 코드가 어떤 것을 의미하는지, 왜 사용해야 하는지, 그냥 남들이 다 쓰길래 사용하는 것은 아닌지 다시 한 번 생각하면서 코드를 짜야겠다고 느꼈다.