에브리타임 클론코딩을 하면서 2번의 CORS 에러에 맞닥뜨렸습니다. 첫번째는 처음 배포할 때, 두번째는 소셜 로그인을 구현할 때입니다. CORS 에러는 왜 발생한 것일까요? CORS 정책이 어떤 것인지 이제서야 정리해보려고 합니다.
웹에는 출처라는 개념이 있습니다. 리소스를 어디서 가져오는지에따라 same-origin과 cross-origin으로 나뉩니다.

이렇게 URL에서 프로토콜,호스트,포트를 체크하여 같은 출처만을 허용합니다. 다른 리소스를 쓰다가 혹시 모를 해킹 등에 당할 수 있기 때문이죠. 이러한 정책을 동일 출처 정책(Same-origin Policy, SOP)이라고 합니다. 내꺼만 써서 잠재적인 모든 해킹이나 공격을 막겠다!는 거죠.
그런데 프론트엔드 개발을 하다보면 SOP를 모두 지키기에는 너무 제한사항이 많습니다. 특히, 백엔드와 통신을 해야하는데 백엔드 서버는 프론트 서버와 다른 곳에 위치하거든요. 어쩔 수 없이 cross-origin인 리소스들을 써야합니다. 어떻게 해야할까요?
다른 곳의 리소스를 사용하기 위한 규칙중 하나가 바로 CORS(cross-origin resource sharing) 규칙입니다. HTTP response에 Access-Control-Allow-Origin 헤더를 포함하여 다른 출처의 리소스 사용을 허용하는 것입니다.
따라서, 백엔드쪽에서 HTTP response, 즉 서버 측 응답에서 접근 권한을 주는 header를 포함해서 줘야합니다.
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*"); // 모든 도메인
res.header("Access-Control-Allow-Origin", "https://example.com"); // 특정 도메인
});
이런 식으로 말이죠. 처음에는 이게 프론트문제인줄 알고 저희끼리 엄청 고민한 기억이 있네요.
만약 서버에서 이 헤더를 추가할 수 없는 상황이라면 어떻게 할까요? 또는, 배포 전 로컬 환경에서의 CORS 에러를 해결하려면 어떻게 해야할까요? 프로젝트 당시 저희는 클라이언트 단에서의 프록시 서버를 설정하여 웹-서버가 아닌 서버-서버의 통신으로 CORS 에러를 피했습니다. 물론 s3로 배포한 뒤에는 위에서 제시된 헤더를 통해 해결이 된 상태였구요.
"proxy": "http://localhost:3000"
CRA에서는 위의 코드를 package.json에 추가해주면 프록시 서버가 설정됩니다. 더 자세한 사항은 CRA 공식문서를 참고해주세요.
https://create-react-app.dev/docs/proxying-api-requests-in-development/
Proxying API Requests in Development | Create React App
Note: this feature is available with react-scripts@0.2.3 and higher.
create-react-app.dev
프록시 서버를 이용한 우회의 경우는 배포 전 개발 시에만 적용이 된다는 점 알아두세요! s3등에 올리게 되면 html, css, js만 올라가고 정작 프로그램을 돌릴 컴퓨터가 없기 때문이죠.
이렇게 CORS 에러는 다시 안볼 줄 알았습니다. 그런데 소셜로그인에서 다시 한번 나타나더군요. 발생 원인은 다음과 같았습니다.
(1) 클라이언트에서 서버로 API 콜
(2) 소셜 로그인 페이지로 리다이렉트
(3) 로그인 성공하면 서버가 인가코드를 받아서 access_token을 카카오에서 발급
(4) 해당 token을 바탕으로 카카오에서 유저 정보를 서버로 가져오고 프론트로 보냄
이러면 CORS에러가 발생하게 됩니다.
이 방식을 (2)번 과정에서 받은 인가코드를 프론트로 url 쿼리 형식으로 전송하도록 변경하였습니다. 쿼리로 받아온 oauth 정보를 다시 서버에 post하는 방식으로 구현하였습니다.
이렇게 했더니 CORS 에러는 나지 않았습니다. 소셜 로그인 등 외부 API를 쓸 때에는 프론트에서 바로 요청하기보다는 백에서 요청하는 것이 좋을 듯합니다.
'Me > FrontEnd' 카테고리의 다른 글
[JavaScript] JS가 싱글스레드임에도 비동기 처리가 가능한 이유 (0) | 2022.05.19 |
---|---|
[JavaScript] Promise와 async/await (0) | 2022.05.16 |
[JavaScript] 호이스팅과 var,let,const (0) | 2022.05.11 |
[JavaScript] const, let, var의 차이점 (0) | 2022.05.05 |
[JavaScript] 콜백함수(Callback function)과 비동기처리 (0) | 2022.04.30 |
댓글