CORS 오류 3분 만에 해결하는 실전 코드 3개
CORS 오류 때문에 몇 시간을 허비한 적이 있나요? fetch API 요청을 보냈는데 갑자기 빨간색 에러 메시지가 뜨면서 "Access-Control-Allow-Origin" 운운할 때의 그 막막함, 저도 너무 잘 압니다. 이 문제를 3분 만에 해결할 수 있는 실전 코드 3개를 준비했습니다.
원리는 간단합니다. 브라우저가 보안상 다른 출처의 요청을 막는 것인데, 서버에서 "이 출처는 괜찮아"라고 알려주는 헤더를 한 줄 추가하면 끝입니다.
CORS 오류가 발생하는 정확한 이유
CORS(Cross-Origin Resource Sharing) 오류가 뜨는 이유는 우리나라 브라우저가 SOP(Same Origin Policy)를 강제하기 때문입니다. SOP는 같은 출처(프로토콜, 도메인, 포트가 모두 같은 경우)의 리소스만 주고받도록 제한하는 보안 정책입니다.
예를 들어 http://localhost:3000에서 실행 중인 프론트엔드가 http://api.example.com으로 fetch 요청을 보내면, 두 출처가 다르므로 브라우저가 요청을 차단합니다.
- SOP는 기본 보안 정책으로, 제3자 웹사이트가 사용자 데이터를 가로채는 것을 방지
- CORS는 이 제한을 완화하는 HTTP 헤더 기반 메커니즘
- 브라우저는 preflight 요청(OPTIONS 메서드)을 먼저 보내 서버가 CORS를 허용하는지 확인
- 서버가 적절한 응답 헤더를 보내지 않으면 실제 요청도 차단
PHP 서버에서 CORS 허용하는 가장 빠른 방법
PHP로 작성된 백엔드가 있다면 header() 함수 한 줄이면 해결됩니다. 다른 출처의 요청을 모두 허용하려면 아래 코드를 응답을 보내기 전에 추가하세요.
header("Access-Control-Allow-Origin: *");
이 코드 하나면 모든 출처에서 오는 요청을 허용합니다. 하지만 보안에 민감한 경우라면 와일드카드(*) 대신 실제 요청을 허용할 출처를 명시하는 게 좋습니다.
Access-Control-Allow-Origin: *— 모든 출처 허용Access-Control-Allow-Origin: https://myfrontend.com— 특정 출처만 허용- 응답 헤더는
header()함수로echo나print보다 먼저 설정해야 적용됨
세션 인증까지 유지하려면 credentials 설정이 필수
일반적인 CORS 설정만으로는 로그인 상태를 유지하기 어렵습니다. 왜냐하면 세션 ID는 쿠키를 통해 전달되는데, 브라우저가 기본적으로 교차 출처 요청에서 쿠키를 포함하지 않기 때문입니다.
이 문제를 해결하려면 프론트엔드와 백엔드 양쪽에서 credentials 관련 설정이 필요합니다.
프론트엔드 fetch 코드
fetch('http://api.example.com/data', {
method: 'GET',
credentials: 'include', // 세션 쿠키를 함께 전송
mode: 'cors'
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('CORS 오류:', error));
credentials: 'include'는 요청에 쿠키를 포함시키라는 옵션입니다. mode: 'cors'는 기본값이지만 명시적으로 작성해도 좋습니다.
백엔드 PHP 코드
header("Access-Control-Allow-Origin: https://myfrontend.com");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
여기서 반드시 지켜야 할 규칙이 있습니다. Access-Control-Allow-Origin에 와일드카드(*)를 사용하면 Access-Control-Allow-Credentials: true와 함께 쓸 수 없습니다.
브라우저가 이 조합을 거부하기 때문에 반드시 구체적인 출처를 적어야 합니다.
credentials: 'include'없으면 세션 쿠키가 전송되지 않아 인증 실패Access-Control-Allow-Credentials: true는 서버가 쿠키를 받아들일 준비가 되었음을 알림- 와일드카드
*와 credentials 설정은 함께 사용 불가 — 반드시 출처를 구체적으로 지정
자주 묻는 질문
Q. mode: 'no-cors'를 쓰면 모든 CORS 문제가 해결되나요?
no-cors 모드는 CORS 오류 자체를 안 뜨게 하지만, 응답 데이터를 자바스크립트에서 읽을 수 없게 만듭니다. 즉, 요청은 보내지지만 응답 본문이 opaque 상태가 되어 데이터를 사용할 수 없습니다.
단순히 GET 요청을 보내고 결과를 무시해도 되는 상황이 아니라면 추천하지 않습니다.
Q. 프리플라이트(OPTIONS) 요청에 대한 처리는 어떻게 하나요?
브라우저가 실제 요청보다 먼저 OPTIONS 메서드로 확인 요청을 보냅니다. PHP에서는 아래와 같이 OPTIONS 요청을 먼저 처리하고, 적절한 CORS 헤더를 반환해야 합니다.
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header("Access-Control-Allow-Origin: https://myfrontend.com");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 86400");
http_response_code(200);
exit;
}
Q. CORS 오류가 계속 발생하는데 어디부터 점검해야 할까요?
브라우저 개발자 도구의 네트워크 탭을 열고 요청과 응답 헤더를 확인하는 것이 가장 빠릅니다. 응답 헤더에 Access-Control-Allow-Origin이 있는지, 값이 프론트엔드 출처와 일치하는지 확인하세요.
만약 OPTIONS 요청이 404나 500으로 떨어진다면 서버에서 OPTIONS 메서드를 처리하지 못하는 경우입니다.



댓글
댓글 쓰기