반응형
"POST 요청을 보냈는데, 웬 OPTIONS 요청이 먼저 가더니 CORS 에러가 났어요!"
프론트와 백엔드 협업 중 자주 듣는 말이죠. 이 글에서 그 정체를 파헤쳐 보겠습니다.
🚀 Preflight 요청이란?
Preflight는 말 그대로 "사전 요청"입니다.
브라우저는 보안상 민감하거나 위험할 수 있는 요청에 대해, 먼저 서버에게 OPTIONS 메서드로
"이 요청을 보내도 괜찮을까요?" 하고 물어보는 절차를 거칩니다.
즉, 본 요청 전에 보내는 사전 검사용 요청입니다.
🔍 언제 Preflight가 발생할까?
- 요청 방식이 GET/POST 외의 메서드일 때 (예: PUT, DELETE)
- Content-Type이 application/json 등 일반적인 타입이 아닐 때
- 사용자 지정 헤더 (예: Authorization) 를 사용할 때
→ 이 조건에 해당하면 브라우저는 자동으로 OPTIONS 요청을 먼저 보냅니다.
📡 실제 네트워크 요청 흐름 예시
리액트에서 다음과 같은 POST 요청을 보냈다고 가정해보세요:
fetch('http://localhost:8080/api/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token'
},
body: JSON.stringify({ name: 'John' })
});
→ 브라우저는 먼저 아래와 같은 OPTIONS 요청을 서버에 보냅니다:
OPTIONS /api/data HTTP/1.1
Origin: http://localhost:3000
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization
서버는 이 요청에 대해 다음과 같이 응답해야 합니다:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
🧱 서버가 응답을 누락하면?
브라우저는 본 요청을 아예 보내지 않고 CORS 에러를 발생시킵니다.
Access to fetch at 'http://localhost:8080/api/data' from origin 'http://localhost:3000'
has been blocked by CORS policy...
🔧 해결 방법
✅ Spring Boot
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*");
}
}
✅ Node.js (Express)
const cors = require('cors');
app.use(cors({
origin: 'http://localhost:3000',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
✅ Nginx 프록시 설정
location / {
if ($request_method = OPTIONS ) {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS, PUT, DELETE';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
return 204;
}
}
🙅♂️ 잘못된 해결 방식
- OPTIONS 요청을 백엔드에서 막아버림 ❌
- 브라우저 확장 프로그램으로 우회 ❌
- Access-Control-Allow-Origin: * 로 모두 허용 (보안상 위험) ❌
📌 정리
항목 | 내용 |
---|---|
Preflight란? | 본 요청 전에 OPTIONS로 서버 허용 여부 확인 |
발생 조건 | PUT/DELETE, application/json, Authorization 헤더 등 |
누가 보냄? | 브라우저 (자동) |
해결 방법 | 서버에서 OPTIONS 허용 및 응답 헤더 추가 |
반응형
'개발일기' 카테고리의 다른 글
Flutter 생명주기 완전 정리: initState부터 dispose까지 (10) | 2025.06.01 |
---|---|
Flutter 위젯 구조 완전 정리: Stateless vs Stateful 차이 (7) | 2025.05.31 |
HTTP 쿠키 vs 세션 완전 정리: 개념, 차이점, 보안까지 (18) | 2025.05.29 |
REST API란? 실무에서 꼭 알아야 할 5가지 핵심 개념 정리 (20) | 2025.05.28 |
프론트와 백엔드 협업 시 API 명세 잘 만드는 법: 실무에서 바로 쓰는 작성 팁 (21) | 2025.05.27 |