IT 개발2026-05-26

CORS 에러 해결 방법: 원인과 서버 설정, 개발 프록시 정리

CORS 에러는 브라우저가 다른 출처의 응답 읽기를 막은 결과이고, 콘솔의 Reason 문구가 원인을 알려 줍니다.

CORS 에러 해결 방법: 원인과 서버 설정, 개발 프록시 정리 썸네일

안녕하세요. 사랑받는 IT 프로덕트의 첫걸음, 똑똑한개발자입니다.

오늘의 인사이트 요약

  1. CORS 에러는 브라우저가 다른 출처의 응답 읽기를 막은 결과이고, 콘솔의 Reason 문구가 원인을 알려 줍니다.

  2. CORS 에러 해결 방법의 근본은 서버 설정입니다. Access-Control-Allow-Origin에 요청 출처를 적고 preflight 요청에도 성공 응답을 내립니다.

  3. 프론트의 개발 서버 프록시는 운영 환경에 적용되지 않습니다.


로컬에서 잘 되던 API 호출이 배포하면 붉은 에러로 바뀌는 일이 흔합니다. 이 글은 CORS 에러 해결 방법을 원인, 서버 설정, 프론트 프록시 순서로 정리했습니다.

CORS란? 브라우저가 다른 출처의 응답을 읽는 규칙입니다

CORS 에러 해결 방법 - 출처가 다르면 브라우저가 응답 읽기를 막는 구조

CORS는 Cross-Origin Resource Sharing의 약자로, 다른 출처의 응답을 읽어도 되는지 브라우저가 확인하는 규칙입니다. 출처를 정하는 건 프로토콜, 도메인, 포트 세 가지라서 http://localhost:3000의 화면이 https://api.example.com을 부르면 셋이 모두 달라 다른 출처가 됩니다.

단순 요청은 응답 읽기가, 사전 요청은 본 요청 전송이 막힐 수 있습니다.

위 그림은 사전 요청이 없는 경우를 단순화한 예입니다. 단순 요청은 서버까지 도달해도 허용 헤더가 없으면 자바스크립트가 응답을 읽지 못합니다. 반면 preflight가 실패하면 본 요청 자체가 전송되지 않을 수 있습니다. 규칙을 적용하는 주체는 브라우저이지만, 원인은 서버·프록시의 허용 설정이나 네트워크 문제일 수 있습니다.

이유는 콘솔의 Reason에 적혀 있습니다.

콘솔 오류와 네트워크 탭을 함께 보면 어느 단계에서 실패했는지 알 수 있습니다. Postman이나 curl은 브라우저의 CORS 제한을 적용하지 않으므로, 해당 도구에서 성공했다는 사실만으로 브라우저 설정까지 정상이라고 볼 수는 없습니다. MDN CORS 가이드

단순 요청과 preflight는 이렇게 갈립니다

CORS 에러 해결 방법 - 단순 요청과 preflight 흐름 비교

메서드가 GET, HEAD, POST 중 하나이고 Content-Type이 application/x-www-form-urlencoded, multipart/form-data, text/plain등의 조건을 충족하면 단순 요청에 해당합니다. 직접 붙인 헤더도 안전한 목록에 있어야 하며, 하나라도 벗어나면 브라우저가 preflight를 먼저 보냅니다.

preflight는 OPTIONS 메서드로 먼저 물어봅니다.

브라우저가 Access-Control-Request-Method와 Access-Control-Request-Headers를 보내면 서버는 Access-Control-Allow-Methods와 Access-Control-Allow-Headers로 답해야 합니다. Content-Type: application/json을 쓰는 API 호출은 대부분 여기에 해당합니다. 결과는 Access-Control-Max-Age만큼 캐시되고 기본값은 5초입니다.

CORS 에러 해결 방법의 근본은 Access-Control-Allow-Origin 서버 설정입니다

CORS 에러 해결 방법 - 콘솔 문구별 원인과 서버 설정 수정 방향

MDN이 정리한 파이어폭스 콘솔 문구 기준입니다.

콘솔 Reason

원인

고칠 곳

Access-Control-Allow-Origin missing

응답에 허용 헤더 없음

서버가 헤더를 내려줌

Credential is not supported ... '*'

쿠키 요청에 와일드카드

요청 출처를 정확히 지정

preflight channel did not succeed

OPTIONS 요청 실패

OPTIONS에 허용 헤더로 응답

쿠키를 쓰면 와일드카드를 쓸 수 없습니다.

쿠키 요청이라면 MDN 설명대로 * 대신 출처를 적어야 합니다. 프론트는 credentials: "include", 서버는 Access-Control-Allow-Credentials: true로 답하고 출처가 바뀌면 Vary: Origin도 보냅니다.

Express에서는 cors 미들웨어에 허용 출처를 지정합니다.

아래는 Express 앱에 cors 미들웨어를 가져온 뒤 사용하는 설정 예시입니다. 실제 서비스의 허용 도메인으로 바꾸고 라우터보다 앞에 적용합니다. 출처를 동적으로 응답할 때도 받은 Origin을 무조건 복사하지 않고 허용 목록과 대조합니다.

app.use(cors({ origin: ["https://app.example.com"], credentials: true }));

Spring은 @CrossOrigin이나 addCorsMappings로 설정합니다.

개발 환경에서는 프록시로 같은 출처의 경로를 사용할 수 있습니다

CORS 에러 해결 방법 - 개발 서버 프록시 흐름

서버를 당장 고칠 수 없다면 프록시를 씁니다. 브라우저는 같은 출처인 개발 서버만 부르고 개발 서버가 API를 대신 호출합니다. Vite는 server.proxy에 적습니다.

server: { proxy: { '/api': { target: 'https://api.example.com', changeOrigin: true } } }

프록시는 개발 서버에서만 동작합니다.

Vite 문서에도 이 영역의 옵션은 개발 환경에만 적용된다고 나와 있어서, 운영에서는 같은 도메인 아래 리버스 프록시로 묶거나 서버 설정을 따로 해야 합니다.

no-cors는 JSON 응답을 읽기 위한 해결책이 아닙니다.

mode: "no-cors"는 사용할 수 있는 메서드·헤더를 제한하고, 교차 출처 응답을 opaque 응답으로 만듭니다. 자바스크립트에서는 상태 코드가 0으로 보이고 본문을 읽을 수 없어, API의 JSON 데이터를 쓰려는 목적에는 맞지 않습니다.

CORS 에러 해결 방법, 점검은 이 순서로 합니다

콘솔 Reason을 먼저 읽은 다음 네트워크 탭에서 OPTIONS 요청이 성공했는지 보고 응답의 허용 헤더를 확인합니다. 쿠키를 쓴다면 와일드카드 여부도 봅니다.

개발·스테이징·운영 출처를 구분해 기록하면 배포 후에만 발생하는 오류를 찾기 쉽습니다. CORS는 로그인이나 접근 권한을 대신하는 장치가 아니므로 API 인증·인가도 별도로 적용합니다.

CORS 에러 해결 방법 - 점검 순서 체크리스트

화면과 API가 자연스럽게 이어지도록

웹 서비스를 만들다 보면 화면 개발과 API 연동을 따로 생각하기 쉽습니다. 똑똑한개발자는 웹·앱 기획과 개발을 함께하며, 사용자 화면이 어떤 데이터를 주고받는지부터 배포 환경까지 살펴봅니다.

똑똑한개발자 소개

새 서비스를 준비하면서 로그인이나 외부 API 연결이 고민이라면, 현재 구성과 필요한 기능을 알려주세요. 서비스에 맞는 연결 방식을 함께 이야기해 볼 수 있습니다.

감사합니다. :)

클립보드에 복사되었어요 ✓
이 글을 공유해보세요!