프로그래밍/HTML, Javascript, CSS

CORS preflight 캐시 기준

포도알77 2026. 9. 24. 22:21

CORS preflight cache는 브라우저가 같은 교차 출처 요청을 보낼 때 매번 OPTIONS 확인을 반복하지 않도록 preflight 결과를 잠시 저장하는 별도 캐시입니다. 일반 HTTP 응답 캐시와 같은 저장소가 아니며, 서버가 응답한 Access-Control-Max-Age와 브라우저의 내부 제한을 함께 받습니다.

2026년 9월 24일 확인 기준 MDN과 Fetch Standard는 preflight 요청을 브라우저가 자동으로 보내는 OPTIONS 확인 절차로 설명합니다. 실제 요청의 method와 custom header가 허용되는지 먼저 확인하고, 통과하면 그 다음에 실제 요청을 보냅니다.

preflight는 언제 생기나

모든 CORS 요청이 preflight를 보내는 것은 아닙니다. 단순 요청 범위를 벗어나는 method, 특정 Content-Type, 또는 custom request header가 있으면 브라우저가 실제 요청 전에 서버에 확인합니다. 이때 브라우저는 Origin, Access-Control-Request-Method, 필요하면 Access-Control-Request-Headers를 담은 OPTIONS 요청을 보냅니다.

서버는 이 요청에 대해 Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers 같은 응답 헤더로 허용 범위를 알려 줍니다. 응답이 허용 조건을 만족해야 실제 요청이 이어집니다.

OPTIONS /api/orders HTTP/1.1
Origin: https://app.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-client-version

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, X-Client-Version
Access-Control-Max-Age: 600
Vary: Origin

위 응답은 https://app.example에서 오는 POST 요청과 두 요청 헤더를 허용한다는 뜻입니다. Access-Control-Max-Age: 600은 이 preflight 결과를 최대 600초 동안 재사용할 수 있음을 나타냅니다.

preflight cache는 무엇을 저장하나

Fetch Standard는 사용자 에이전트가 CORS-preflight cache를 가진다고 설명합니다. 이 캐시의 항목에는 네트워크 파티션 키, 요청 origin, URL, max-age, credentials 여부, method, header name 같은 값이 들어갑니다. 그래서 같은 URL이라도 origin, credentials mode, method, header 구성이 달라지면 이전 결과를 그대로 쓸 수 없습니다.

중요한 점은 이 캐시가 일반 HTTP cache와 분리되어 있다는 것입니다. MDN도 preflight 응답은 브라우저의 일반 HTTP cache에 저장되지 않고, preflight 전용 캐시를 사용한다고 설명합니다. 따라서 Cache-Control을 길게 준다고 preflight cache 기간이 늘어나는 식으로 이해하면 안 됩니다.

구분 일반 HTTP cache CORS preflight cache
주요 목적 응답 본문과 헤더 재사용 CORS 허용 확인 결과 재사용
대표 제어 헤더 Cache-Control, ETag, Expires Access-Control-Max-Age
저장 대상 문서, API 응답, 이미지 등 허용된 method와 request header 조건
주의점 캐시 정책과 재검증 조건을 함께 봄 브라우저가 자체 상한이나 조기 삭제를 적용할 수 있음

Access-Control-Max-Age는 얼마나 주면 될까

Access-Control-Max-Age 값은 초 단위입니다. MDN의 CORS 문서는 값이 없을 때 기본값을 5초로 설명하고, 브라우저마다 내부 최대값이 있어 서버가 더 큰 값을 보내도 그 상한이 우선될 수 있다고 설명합니다. Fetch Standard도 Access-Control-Max-Age가 없거나 해석에 실패하면 5로 보고, 부과된 한도를 넘으면 그 한도로 낮춘다고 규정합니다.

따라서 실무 기준은 단순합니다. CORS 정책이 자주 바뀌거나 권한 경계가 민감한 API라면 짧게 잡는 편이 안전합니다. 반대로 method와 header 정책이 안정적인 공개 API라면 몇 분 단위로 두어 불필요한 OPTIONS 왕복을 줄일 수 있습니다. 다만 아주 긴 값을 넣어도 브라우저 상한 때문에 그대로 적용된다고 기대하면 안 됩니다.

상황 Max-Age 판단 이유
개발 또는 정책 변경이 잦은 API 짧게 설정하거나 생략 잘못된 허용 정책이 오래 남는 일을 줄이기 위해서
일반적인 내부 웹앱 API 몇 분 단위부터 검토 변경 반영성과 왕복 감소 사이의 균형을 잡기 쉬움
정책이 안정적인 공개 API 더 긴 값 검토 반복 요청에서 preflight 비용을 줄일 수 있음
origin allowlist를 동적으로 반영 Vary: Origin도 함께 확인 origin별 응답이 섞이지 않도록 캐시 계층에 알려야 함

OPTIONS를 줄이는 것과 CORS를 푸는 것은 다르다

Access-Control-Max-Age는 이미 허용된 preflight 결과를 얼마나 재사용할지 정합니다. 허용되지 않는 origin, method, header를 허용으로 바꾸는 기능은 아닙니다. 예를 들어 서버가 Authorization 요청 헤더를 허용하지 않는다면 max-age를 길게 줘도 실제 요청은 진행되지 않습니다.

또한 preflight가 보인다는 이유만으로 무조건 없애야 하는 것도 아닙니다. custom header를 줄이거나 요청을 단순 요청 범위에 맞추면 preflight 자체가 줄 수 있지만, 보안과 API 설계를 흐리면서까지 피할 대상은 아닙니다. 반복되는 같은 조건의 요청이 많다면 먼저 허용 정책을 정확히 만들고, 그 다음 Access-Control-Max-Age로 왕복 비용을 줄이는 순서가 더 안전합니다.

운영에서 확인할 기준

첫째, 실제 요청과 preflight 요청을 구분해서 봐야 합니다. 브라우저 개발자 도구나 서버 로그에서 OPTIONS가 실패한다면 본 요청의 status code를 보기 전에 CORS 허용 헤더가 맞는지 확인해야 합니다.

둘째, 허용 origin을 요청에 따라 동적으로 반사하는 구조라면 Vary: Origin을 함께 봅니다. MDN은 단일 origin을 명시하거나 allowlist에 따라 동적으로 바꾸는 경우 응답이 Origin 값에 따라 달라진다는 사실을 알려야 한다고 설명합니다.

셋째, 브라우저 캐시 삭제나 탭 새로고침만으로 preflight cache 상태를 정확히 제어한다고 가정하지 않는 편이 좋습니다. Fetch Standard는 preflight cache 항목이 max-age가 지난 뒤 제거되어야 하지만 그 전에도 제거될 수 있다고 설명합니다. 디버깅할 때는 브라우저별 동작 차이를 열어 두고 봐야 합니다.

FAQ

Q. Cache-Control: max-age=600이면 preflight도 600초 캐시되나?

아닙니다. preflight 결과 캐시는 일반 HTTP cache와 분리되어 있고, 기준 헤더는 Access-Control-Max-Age입니다.

Q. preflight cache가 있으면 인증이 생략되나?

아닙니다. preflight cache는 CORS 허용 확인 결과만 재사용합니다. 실제 요청의 쿠키, 토큰, 서버 권한 검사는 별개의 문제입니다.

Q. max-age를 아주 길게 주면 항상 성능이 좋아지나?

항상 그렇지는 않습니다. 브라우저 내부 상한이 있고, CORS 정책을 잘못 배포했을 때 되돌림이 늦어질 수 있습니다. 정책이 안정적인 API에서만 길게 검토하는 편이 안전합니다.

CORS preflight cache의 핵심은 OPTIONS 확인 비용을 줄이되, 허용 정책 자체를 흐리지 않는 것입니다. 서버는 실제로 허용할 origin, method, header를 정확히 응답하고, 반복 요청 비용이 문제일 때 Access-Control-Max-Age를 조정합니다. 일반 HTTP cache와 별도라는 점, 브라우저 상한이 있다는 점, 동적 origin 응답에는 Vary: Origin이 필요할 수 있다는 점을 함께 보면 운영 판단이 단순해집니다.

이 글은 2026년 9월 24일 기준 MDN CORS 문서, MDN preflight request 문서, MDN Access-Control-Max-Age 문서, WHATWG Fetch Standard를 바탕으로 정리했습니다.

참고 문서

반응형

'프로그래밍 > HTML, Javascript, CSS' 카테고리의 다른 글

Web Locks API 기준  (0) 2026.09.30
CHIPS Partitioned 쿠키 기준  (0) 2026.09.27
CSS :state() 기준  (0) 2026.09.23
Speculation Rules API 기준  (0) 2026.09.21
CSS style query 기준  (1) 2026.09.20
페이스북으로 공유카카오톡으로 공유카카오스토리로 공유트위터로 공유URL 복사