교차 출처 리소스 공유(CORS)가 뭔데? - 프론트엔드의 숙명 HTTP통신
422 상태코드 오류
프론트단에서 백엔드 서버에 간단한 로그인 요청을 보내는 작업을 하던 중이었다.
header에 Content-type을 담고, body에 유저의 email과 password 정보를 담아서,
로그인 요청을 보내는 것 까지는 성공했다.
하지만 자꾸 422 status 오류가 떴다.
message: "이메일 또는 비밀번호가 일치하지 않습니다."
status: 422
422 상태코드라면 요청의 문법은 올바르게 갔고, 요청의 내용을 수정할 필요가 있다는 뜻이었다.
분명 실습용 사이트에 존재하는 이메일과 비밀번호인데.
실습 사이트에 몇 번이고 로그인과 로그아웃을 반복하다가 문득 생각했다.
저 서버에 진짜로 존재하지 않는 이메일이라서 오류가 나는거라면?
내가 엉뚱한 서버로 요청을 보내고 있는 거라면?
정말 엉뚱한 서버로 가고 있었구나
정말이었다.
우리가 이용할 수 있는 백엔드 서버가 두 가지였는데,
하나는 IP주소 형식 -ex)192.168.123.132:3000- 이었고,
다른 하나는 도메인 주소 형식 -ex)dontbuycat.co.kr- 이었다.
주소 형식만 다른 같은 서버겠거니 생각했는데. 두 서버는 별개의 서버였다.
나는 IP 주소 서버를 사용하는 사이트에서 만든 아이디를 들고, 도메인 주소에다가 로그인 시켜달라는 요청을 보내고 있었다.
전자의 집에서 아이디를 생성했다면, 아이디가 생성된 곳과 똑같은 집에다가 요청을 보내는 것이 당연했다.
다른 집에서 생성된 요청을 들고, 엉뚱한 집 문을 두드린 것이나 마찬가지였던 것이다...
따라서 요청을 보내는 주소를 IP주소로 변경했다.
결과는 성공!
...일 줄 알았는데
CORS가 뭔데?
Access to XMLHttpRequest at 'http://000.00.000.00:3000/user/login' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
이번엔 CORS 정책에 의해 내 요청이 블락되었다는 오류를 만났다.
어떤 정책인지 알아야 해결을 할 수 있을 것 아닌가. CORS가 뭔데요? 제가 뭘 잘못했나요?
CORS - 교차 출처 리소스 공유
CORS란 Corss-Origin Resource Sharing의 줄임말로, 교차 출처 리소스 공유를 뜻한다.
특정 출처(Origin)에서 실행중인 웹앱이 다른 출처의 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다.
예전에는 같은 도메인에서 request와 response가 일어나는 상황이 일반적이었다. 다른 도메인에서 접근하려면 JSONP라는 우회를 사용했다고 한다.
하지만 웹이 단순히 문서 제공 용도를 넘어, 점점 웹앱 등으로 확장되기 시작했다. 자연스레 다른 도메인간에 상호작용할 일이 많아진 것이다. 브라우저에서는 이런 우회를 방치할 수는 없었지만 수요가 너무 많았다.
따라서 웹브라우저에서 공식적인 CORS라는 루트를 만들어 주었다고 한다.
CORS는 브라우저에서 구현되어 있는 스펙이기 때문에,
CORS 정책을 위반하는 요청을 보냈을 때
1. 서버에서는 정상적인 응답을 보냈지만 브라우저에서 막힌건지
2. 서버에서부터 오류를 보낸건지 알 방법은 없었다.
확실한건 나는 다른 도메인으로 요청을 보내고 있고, 지금 브라우저에서 내 응답이 버려지고 있다는 것이었다.
시도해 본 방법들
구글을 뒤져 프론트단에서 CORS오류를 해결하는 방법을 찾아보았다.
1. package.json에 proxy 수동 설정
결과는 실패. 요청을 보내는 곳과 똑같은 주소로 proxy를 설정해도 계속 CORS오류가 떴다.
2. http-proxy-middleware설치 후 proxy middleware를 생성해 수동 설정
이것도 실패. 미들웨어가 안 먹나? 싶어서 몇 번이고 경로를 확인했지만, 역시 CORS 오류가 떴다.
너무 답답하다. 어디가 문제지?
프록시를 우회하는 온갖 방법을 써 봐도 결과는 실패였다.
너무 답답해서 결국 백엔드의 주인-멋사 멘토님-에게 질문을 드렸다.
Q. 192.168.123.132:3000 으로 요청을 보냈는데, 계속 CORS 오류가 뜹니다. 프록시를 우회해도 해결이 되지 않습니다. 뭘 잘못한건가요?
A. 그곳은 프론트페이지 포트입니다... 백엔드 포트는 :5050 입니다.
결론 : 오류를 만나면 가장 상위 전제까지 천천히 원인을 짚어나가자.
허무하면서 너무 기뻤다. 포트를 5050으로 바꾸자마자 요청이 성공했다.
CORS에서의 '출처(Origin)'는 URL의 Scheme과 Host, 그리고 Port까지 포함한다.
그러니 출처부터 막히는 것은 당연했다...
서버에서 교차 출처를 막아두지 않았더라도, 데이터에 접근할 수는 없었을 것이다. 프론트 포트에는 데이터가 없을테니 당연하다.
두 URL이 다른 DB를 사용한다는 것 까지는 생각해냈는데, URL의 포트가 문제일 줄은 짐작도 못 했다.
오류가 발생하면, 가장 아랫단계부터 가장 상위의 전제-당연하다고 짚고 넘어가는 부분-까지 차근차근 짚어 올라가야겠다고 느꼈다.
물론 HTTP 통신에 관한 공부를 더 해야겠다고 느낀 건 당연하다.
프론트엔드를 하기로 마음을 먹었다면
브라우저와 친해지고, HTTP 통신 지식을 쌓는 것은 피할 수 없는 일인 것 같다.
그리고 모르면 물어보자. 물어볼 환경이 된다는 것에 감사하자.
CORS로 하루를 꼬박 날리고 나니, 답답해서 누군가에게든 물어보고 싶은 마음이었다.
질문을 통해 해결까지 하고 나니 질문의 힘을 체감했다.
부트캠프 안에서 동기분들과 선생님들, 멘토님들에게 물어볼 수 있는 환경이 너무 감사했다.
왠만하면 스스로 해결하려하는 독학에 특화된 사람이지만,
컴퓨터랑 대화하다가 안되면 사람과 대화하는 것이 때로는 해결책일 수 있겠구나.
사람과도 커뮤니케이션이 원활한 인간친화적 개발자가 되자고 다짐했다.
참고한 글
React 개발환경에서의 CORS를 위한 proxy 설정
9. CORS 와 Webpack DevServer Proxy