← 모두의 툴

CORS 프리플라이트(OPTIONS)는 언제 발생하나 — 3가지 조건

가이드 · 2026.08.26 최종 확인

HTTP 요청 빌더로 cURL·fetch·axios 코드를 만들다 보면 같은 요청인데도 브라우저에서 실행하면 갑자기 CORS 에러가 나거나, 개발자 도구 네트워크 탭에 보낸 적 없는 OPTIONS 요청이 하나 더 찍혀 있는 걸 볼 수 있습니다. 이게 바로 프리플라이트(preflight)입니다. "언제 뜨는지 감으로만 안다"는 상태에서 벗어나려면 딱 3가지 조건만 외우면 됩니다.

1. 브라우저는 왜 본 요청 전에 미리 물어보나

크로스오리진(다른 도메인) 요청은 서버가 미처 대비하지 못한 상태에서 임의의 사이트가 사용자의 인증 정보(쿠키 등)를 실어 요청을 보낼 위험이 있습니다. 브라우저는 이를 막기 위해 요청을 두 부류로 나눕니다. 폼 제출만으로도 예전부터 가능했던 수준의 요청은 simple request(단순 요청)로 분류해 바로 보내고, 그 범위를 벗어나는 요청은 실제 요청 전에 OPTIONS 메서드로 "이 요청 보내도 되는지" 서버에 먼저 물어봅니다 — 이게 프리플라이트입니다. 서버가 Access-Control-Allow-* 헤더로 허가해야만 본 요청이 나갑니다.

2. simple request를 벗어나는 3가지 조건

아래 셋 중 하나라도 해당하면 무조건 프리플라이트가 발생합니다. 셋을 모두 피해야만 simple request로 처리됩니다.

#조건구체 예시
메서드가 GET/HEAD/POST가 아님PUT, DELETE, PATCH 등
Content-Type이 3종 세이프리스트 밖application/x-www-form-urlencoded, multipart/form-data, text/plain 외 — 대표적으로 application/json
CORS-safelisted 밖의 커스텀 헤더 추가Authorization, X-Custom-Header

이 3가지는 HTTP 요청 빌더 페이지 FAQ에도 그대로 명시돼 있는 조건이며, 실제 도구 코드를 확인한 결과 텍스트로 안내만 할 뿐 빌더 자체가 현재 입력값을 이 조건에 자동으로 대입해 "이 요청은 프리플라이트가 뜹니다"라고 실시간 경고해주지는 않습니다. 즉 판단은 사용자가 표를 보고 직접 해야 합니다.

3. 실무에서 가장 자주 걸리는 조합

REST API를 JSON으로 호출하는 요청은 거의 예외 없이 프리플라이트가 뜹니다. POST 메서드 자체는 세이프리스트 안에 있지만, Content-Type: application/json이 조건 ②에 걸리기 때문입니다. 여기에 Authorization: Bearer 토큰까지 추가하면 조건 ③까지 겹쳐 이중으로 프리플라이트 대상이 됩니다.

구체 예시 — 동일한 POST 요청 두 가지를 비교하면:
요청 구성해당 조건프리플라이트 발생?
POST + Content-Type: application/x-www-form-urlencoded + 헤더 없음없음아니오 (simple request)
POST + Content-Type: application/json + Authorization 헤더②, ③ 동시 해당예 (OPTIONS 먼저 발생)

즉 겉보기엔 둘 다 "POST 한 번"이지만, 네트워크 탭을 열어보면 두 번째 요청만 실제 요청 앞에 OPTIONS 요청 한 번이 추가로 찍힙니다. CORS 헤더 검사기로 서버 응답 헤더에 Access-Control-Allow-Methods, Access-Control-Allow-Headers가 실제로 포함돼 있는지 확인하면 프리플라이트가 실패하는 원인을 빠르게 좁힐 수 있습니다.

4. 프리플라이트 자체는 막을 수 없다 — 설계로 피할 뿐

클라이언트 코드에서 프리플라이트를 "끄는" 옵션은 없습니다. 브라우저가 요청 구성을 보고 자동으로 판단하는 것이라 개발자가 할 수 있는 건 애초에 3가지 조건에 걸리지 않도록 설계하는 것뿐입니다. 다만 실무에서는 JSON API·인증 헤더가 표준이라 프리플라이트를 피하기보다는, 서버가 OPTIONS 요청에 올바른 CORS 헤더로 응답하도록 설정하는 쪽이 현실적인 해법입니다.

자주 묻는 질문

Q. GET 요청도 프리플라이트가 뜨나요?

A. GET 자체는 조건 ①(허용 메서드)에 걸리지 않습니다. 다만 GET 요청에 커스텀 헤더(예: Authorization)를 추가하면 조건 ③에 걸려 프리플라이트가 발생합니다.

Q. Content-Type을 text/plain으로 바꾸면 프리플라이트를 피할 수 있나요?

A. 조건 ②만 놓고 보면 그렇습니다. 하지만 JSON 문자열을 text/plain으로 보내면 서버가 자동으로 JSON 파싱을 안 해줄 수 있어 별도 처리가 필요합니다. 다른 조건(메서드, 커스텀 헤더)이 없어야 실제로 simple request가 됩니다.

Q. 같은 오리진(same-origin) 요청도 프리플라이트가 필요한가요?

A. 아니요. 프리플라이트는 크로스오리진 요청에만 적용되는 개념입니다. 같은 도메인·포트·프로토콜이면 CORS 자체가 개입하지 않습니다.

Q. HTTP 요청 빌더가 프리플라이트 발생 여부를 자동으로 알려주나요?

A. 아니요. 현재 이 빌더는 cURL/fetch/axios 코드 생성과 FAQ 안내만 제공하며, 입력한 요청 구성이 3가지 조건에 해당하는지 실시간으로 판정해주는 기능은 없습니다. 표를 보고 직접 대조해야 합니다.

Q. 프리플라이트가 실패하면 어떤 에러가 뜨나요?

A. 보통 콘솔에 "has been blocked by CORS policy" 형태의 메시지가 뜨고, 네트워크 탭에는 OPTIONS 요청이 실패(또는 403 등)로 표시됩니다. 실제 본 요청은 브라우저가 아예 보내지 않습니다.