[10편] API 호출 시 자주 겪는 CORS(교차 출처 리소스 공유) 에러의 원인과 이해





프론트엔드 개발의 기초를 다지고 자바스크립트의 비동기 처리 방식까지 이해했다면, 이제 내 웹페이지에서 외부 서버와 데이터를 주고받는 API 호출을 시도할 차례다. 리액트나 바닐라 자바스크립트로 멋진 웹 애플리케이션을 만들고 로컬 서버를 띄운 뒤, 백엔드 서버나 외부 공공 API에 데이터를 요청(Fetch)하는 순간 터미널이나 브라우저 개발자 도구 콘솔창에 도저히 눈 뜨고 볼 수 없는 무시무시한 빨간색 에러 문구가 나타난다.

Access to fetch at 'https://api.server.com/data' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

분명히 주소도 정확하게 적었고 인터넷 연결도 정상인데, 브라우저는 이 데이터를 화면에 보여주는 것을 완벽하게 거부한다. 초보 개발자들을 가장 멘붕에 빠뜨리는 악명 높은 'CORS 에러'의 정체다.

[소제목] CORS(교차 출처 리소스 공유)란 무엇이며 왜 막는가

CORS는 Cross-Origin Resource Sharing의 약자로, 우리말로는 '교차 출처 리소스 공유'라고 부른다. 이 에러를 이해하려면 브라우저의 기본 보안 정책인 '동일 출처 정책(Same-Origin Policy, SOP)'부터 알아야 한다.

  • 브라우저는 기본적으로 내가 접속한 웹페이지와 자원을 요청하는 서버의 '출처(Origin - 프로토콜, 도메인, 포트 번호)'가 정확히 일치할 때만 안전하다고 판단하고 데이터를 허용한다.

  • 만약 http://localhost:3000에서 실행 중인 내 프론트엔드 앱이 전혀 다른 주소인 [https://api.server.com](https://api.server.com)으로 데이터를 요청하면, 브라우저는 악의적인 해커가 사용자의 정보를 탈취하려는 시도일 수 있다고 의심하여 그 응답을 강제로 차단해 버린다.

  • 즉, CORS 에러는 서버가 고장 난 것이 아니라, 브라우저가 보안을 위해 사용자(우리)의 요청을 억지로 가로막아서 발생하는 현상이다.

[소제목] CORS 에러를 해결하는 실무적인 방법들

CORS 정책은 브라우저가 강제하는 보안 규칙이기 때문에, 프론트엔드 코드 안에서 무슨 짓을 해도 브라우저 단에서 곧바로 해결하기는 까다롭다. 직접 겪어본 바에 따르면 이 문제를 해결하는 방식은 크게 세 가지로 나뉜다.

  1. 백엔드 서버에서 허용 헤더(Header) 설정하기 (가장 정석적인 방법) API를 직접 개발하거나 백엔드 개발자와 협업하는 상황이라면, 서버 응답 헤더에 Access-Control-Allow-Origin 값을 추가하여 "이 특정 도메인(예: http://localhost:3000)에서 오는 요청은 믿을 수 있으니 허용해 줘"라고 서버가 직접 선언해주어야 한다.

  2. 개발 환경(Vite 또는 Webpack)에서 프록시(Proxy) 설정하기 개인 공부를 하거나 외부 공공 API를 쓸 때 백엔드 코드를 수정할 수 없다면, 프론트엔드 빌드 도구의 프록시 기능을 활용해 우회할 수 있다. 브라우저는 내 로컬 서버(예: localhost:3000)가 다른 곳으로 요청을 보낸다고 생각하지만, 실제로는 개발 서버가 중간에서 대신 요청을 받아 전달해주므로 브라우저의 눈을 감쪽같이 속일 수 있다.

  3. 크롬 브라우저 보안 우회 확장프로그램 사용하기 (개발 중에만 임시로) 급하게 API 응답 구조를 테스트해봐야 할 때는 CORS를 강제로 꺼주는 크롬 확장프로그램을 임시로 켜두기도 한다. 하지만 이는 어디까지나 급할 때 쓰는 방편일 뿐, 실무 서비스나 배포 환경에서는 절대 통하지 않으므로 근본적인 해결책이 될 수 없다.

[소제목] 초보자가 자주 하는 실수와 주의사항

CORS 에러를 처음 마주하면 십중팔구 "내 코드에 오타가 있나?", "비동기 처리를 잘못했나?" 하고 자바스크립트 문법을 한참 동안 들여다보며 시간을 낭비하곤 한다. 에러 메시지에 명확하게 'CORS policy'라는 단어가 박혀 있다면 코드의 문법적 오류가 아니라 네트워크 보안 정책의 문제이므로 방향을 잘못 잡지 않도록 주의해야 한다.

또한, 로컬 개발 환경에서는 프록시 설정을 통해 가볍게 넘어가더라도, 나중에 실제 운영 서버(Production)에 코드를 배포하고 나면 프록시 설정이 풀리면서 다시 CORS 지옥에 빠지는 경우가 허다하다. 따라서 서비스 배포 전에는 반드시 실제 백엔드 서버와 프론트엔드 도메인 간의 허용 정책이 올바르게 맺어져 있는지 거듭 확인하는 습관을 가져야 한다. 처음에는 이 보이지 않는 벽이 원망스럽겠지만, 웹 보안 생태계가 어떻게 돌아가는지 체감하게 해주는 가장 훌륭한 관문이기도 하다.

핵심 요약:

  • CORS 에러는 브라우저의 동일 출처 정책(SOP) 때문에 서로 다른 출처 간의 리소스 공유를 보안상 차단할 때 발생한다.

  • 프론트엔드 단독으로는 브라우저의 차단을 풀기 어렵고, 서버 측의 허용 헤더 설정이나 개발 환경 프록시 우회를 통해 해결해야 한다.

  • 에러 메시지에 'CORS policy'가 포함되어 있다면 문법 오류가 아닌 보안 정책의 문제이므로 서버 설정이나 도메인 관계를 점검해야 한다.

다음 편 예고: 다음 편에서는 SQL 기초: 데이터베이스 조회 시 WHERE와 JOIN 절을 올바르게 쓰는 법을 다룬다.

이 글을 읽으면서 API를 호출하다가 CORS 에러를 만나 곤혹스러웠던 적이 있거나 해결 과정에서 헷갈렸던 점이 있다면 댓글로 편하게 공유해 주세요!

댓글 쓰기

0 댓글

신고하기

프로필

이미지alt태그 입력