CORS - cors Preflight request OPTIONS

2025. 11. 20. 15:03웹 개발 이론

프론트엔드 개발중 cors 를 맞게되었다.

 

상황은 이러하다.

 

나의 경우 유저 검증이 필요한 API들은 로그인시 부여받은 cookie 값으로 jwt 토큰을 다루는데, 서버에 요청은 가지만 GET을 제외한 모든요청에 브라우저는 CORS Preflight 오류를 내뱉고 있었고

 

서버는 쿠키값이 없다는 말만 반복

 

해결방법 먼저 말하자면

    if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
        chain.doFilter(request, response);
        return;
    }

토큰 인증로직에 OPTIONS 메서드는 제외시키는 것.

 

이제 같은 뻘짓으로 시간낭비를 하지않기 위해 이유를 파악해보자

 

먼저 OPTIONS요청은 뭘까 일단 쉽게 설명하자면

실제 요청(POST)

= 밥 먹기

Preflight(OPTIONS) 요청

= “식당 들어가도 되나요?” 물어보기

 

실제 요청 전에 가볍에 물어보는것.

 

이제 본격적으로 알아보자.

 

선 요약 — 핵심 정리

  • OPTIONS는 HTTP 메서드 중 하나이며 “사전 허가 요청(preflight)의 메서드”이다.
  • 브라우저가 CORS 상황에서 실제 요청을 보내기 전에 서버에게 물어보는 절차다.
  • OPTIONS에는 쿠키·인증정보가 없다.
  • 서버는 OPTIONS 요청에서는 인증하지 말고 무조건 통과시켜야 한다.
  • OPTIONS 응답에 CORS 허용 헤더(Origin, Headers, Methods, Credentials)를 포함해 200으로 보내야 한다.
  • 이게 실패하면 CORS 에러가 발생하고 실제 요청조차 보내지지 않는다.

🔥 1. OPTIONS란 무엇인가? — “사전 질문 요청(Preflight)”의 주인공

OPTIONS는 HTTP 메서드 중 하나다.
브라우저가 어떤 요청을 “보내도 안전한지” 서버에게 먼저 묻기 위해 보내는 사전 문의용 요청이라고 보면 된다.

비유

실제 요청(POST, PUT, DELETE)을 보내기 전에
브라우저가 서버에게 이렇게 묻는 거야:
"이런 요청 보내도 괜찮아? 위험하지 않아?"

이 질문이 바로 OPTIONS 요청이다.

 

🔥 2. OPTIONS는 왜 생겼을까? 왜 꼭 필요할까?

브라우저는 보안상 “다른 도메인(origin)”으로 민감한 요청을 보낼때에는 먼저 사전검사용 요청을 보낸다.


예를 들어 악성 사이트가 너의 브라우저를 이용해서 은행 API에 몰래 송금요청을 보내려 한다면?

 

그래서 브라우저는 아래와 같은 안전하지 않은 요청을 보내려고 하면\

그 전에 서버( 예를들어 은행API 를 운영중인 )에게 허락을 받는다.

즉,

  1. 요청이 위험할 수 있을 때
  2. 먼저 OPTIONS로 물어보고
  3. 서버가 OK하면 실제 요청을 보내는 구조

이게 Preflight(사전 요청) 방식이다.

 

🔥 3. 언제 OPTIONS(Preflight)가 발생하나?

다음 조건 중 하나라도 만족하면 발생한다.

1) 메서드가 단순하지 않을 때

단순한 것: GET, POST, HEAD
그 외: PUT, DELETE, PATCH → 무조건 preflight 발생

2) POST라도 Content-Type이 단순하지 않을 때

단순한 것:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

단순하지 않은 경우(즉 JSON) → preflight 발생

  • application/json

3) 커스텀 헤더가 있을 때

예: Authorization, X-User-Id, X-Api-Key → preflight 발생

 

🔥 4. OPTIONS는 어떤 정보를 서버에게 묻나?

브라우저가 OPTIONS 요청에서 서버에게 묻는 질문:

  1. 이 origin이 요청해도 되는지 (Access-Control-Allow-Origin)
  2. 쿠키를 보내도 되는지 (Access-Control-Allow-Credentials)
  3. 어떤 메서드를 허용하는지 (Access-Control-Allow-Methods)
  4. 커스텀 헤더를 써도 되는지 (Access-Control-Allow-Headers)

서버는 이 요청들에 대해 "OK"라고 대답해줘야 한다.

 

🔥 5. OPTIONS 요청 예시

브라우저가 보내는 OPTIONS 요청은 이런 모습이다.

 
OPTIONS /member/login HTTP/1.1 Origin: https://test.domain.com Access-Control-Request-Method: POST Access-Control-Request-Headers: Content-Type
 

의미:

라고 묻는 것.

 

🔥 6. 서버는 뭐라고 답해야 하나?

서버가 허용한다면 아래처럼 답해야 한다:

응답 예시 :
HTTP/1.1 200 OK Access-Control-Allow-Origin: https://test.domain.com Access-Control-Allow-Credentials: true Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: Content-Type Access-Control-Max-Age: 3600
 
 
코드 예시 :
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://test.domain.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 3600​

그러면 브라우저는 이렇게 판단한다:

“아~ 서버가 허용했네. 그럼 이제 진짜 POST 요청 보내자!”

 

 

🔥 7. 왜 OPTIONS가 인증에 걸리면 안 되나?

OPTIONS에는 절대로 쿠키가 포함되지 않는다.
즉 인증정보가 없는 요청이다.

근데 서버에서 OPTIONS 요청을

  • JWT 검사하거나
  • 쿠키 검사하거나
  • 로그인 여부 검사하거나
  • 관리자 권한 확인하거나

하면 무조건 실패한다 → 401, 403 발생

 

그러면 브라우저는 "CORS 실패"라고 표시하고 POST 요청도 아예 보내지 않는다.

그래서 CORS 설정에서

 

OPTIONS는 무조건 인증을 건너뛰어야 한다

나의 경우도 이 경우였고 Preflight( OPTIONS method ) 요청은 검증을 무조건 통과시켰다.
 
성공.
 
 
하나 덧붙이자면
addAllowedOriginPattern("*")
config.setAllowCredentials(true);​

 

setAllowCredentials 값을 true인데 originPattern에 저딴 값이 보인다면 가서 백엔드의 뺨을 갈겨주도록 하자

위의 경우 브라우저가 차단하니

addAllowedOriginPattern("https://test.domain.com")
config.setAllowCredentials(true);
 
 이렇게 정확한 origin 값을 넣어주자
 
 
 
ps. 근데 내부 네트워크에서는 왜 잘 동작했던거지..?

 

'웹 개발 이론' 카테고리의 다른 글

web cookie / session  (0) 2022.11.11
Bootstrap 세팅과 사용법  (1) 2022.10.31
하이브리드 앱 초기 설정/설치 ( android-studio )  (0) 2022.10.12
모바일 해상도 맞추기  (0) 2022.09.28
모바일(유동형) 웹/앱 이론  (0) 2022.09.26