안녕하세요.
로컬 API 테스트할 때 CORS 문제 때문에 개발 흐름 끊기는 거 정말 공감합니다.
저도 처음 이 문제 만났을 때 '왜 항상 이 문제만 생길까' 싶어서 시간 꽤 많이 썼거든요.
결론부터 말씀드리면, '완벽하게 0% 에러'를 만드는 마법 같은 방법은 없고, 사용하는 스택과 테스트 목적에 따라 가장 '덜 짜증 나는' 워크어라운드가 달라집니다.
질문자님이 '효율적'이고 '자동화'되는 방법을 원하시니까, 몇 가지 관점별로 정리해서 최대한 자세히 설명드릴게요.
우선, CORS가 발생하는 근본적인 원리를 다시 한번 짚고 넘어가는 게 중요합니다.
CORS(Cross-Origin Resource Sharing)는 보안 정책입니다.
브라우저가 '원점(Origin)'을 기준으로, 다른 도메인에서 요청이 오면 '혹시 악의적인 요청일까?' 하고 막아버리는 게 기본 작동 원리예요.
프론트엔드(예: http://localhost:3000)가 백엔드 API(예: http://localhost:8080)를 호출할 때, 이 두 주소가 다르면 브라우저가 기본적으로 보안 경고를 띄우고 요청을 차단하는 거죠.
이건 개발자가 '임시로 허용해 줘'라고 설정해주지 않으면 안 되는 구조입니다.
--- ### 1.
가장 일반적이고 추천하는 방법: 개발 환경 프록시 설정 활용 (프론트엔드/빌드 툴 레벨) 만약 프론트엔드 빌드 툴(React의 Create React App이나 Vite 같은 경우)을 사용하고 계시다면, 이 방법이 가장 표준적이고 설정 변경이 적어 추천드립니다.
원리: 프론트엔드 개발 서버(예: Vite)가 마치 중간 게이트웨이 역할을 하도록 설정하는 겁니다.
프론트엔드 코드가 API를 호출할 때, 실제로는 로컬 서버가 아닌 빌드 툴의 개발 서버 주소로 요청을 보내게 하고, 이 개발 서버가 대신 백엔드 API 서버로 요청을 보내준 뒤, 받은 데이터를 다시 프론트엔드로 전달해주는 방식입니다.
이 과정에서 브라우저는 '같은 원점'에서 요청이 온 것으로 인식하기 때문에 CORS 문제가 발생하지 않습니다.
구체적인 구현 예시: * Vite 사용 시: vite.config.js 파일에 server.proxy 설정을 사용합니다.
javascript // 예시 설정 (실제 프로젝트 구조에 맞게 수정 필요) server: { proxy: { '/api': { target: 'http://localhost:8080', // 백엔드 서버 주소 changeOrigin: true, // 호스트 헤더를 변경하여 API 서버가 요청을 받을 수 있게 해줌 secure: false, }, }, }, 이렇게 설정하면, 프론트엔드 코드에서 axios.get('/api/users') 라고 호출해도, 실제로는 http://localhost:8080/users로 요청이 가지만, 브라우저 입장에서는 http://localhost:3000/api/users에서 온 것처럼 처리됩니다.
- Create React App (CRA) 사용 시:
package.json에 proxy 키를 추가하는 방식이 가장 간단합니다.
json // package.json "proxy": "http://localhost:8080" 이렇게 설정하면, /api 접두사 없이 호출할 경우(예: axios.get('/users')) 자동으로 백엔드 서버로 리다이렉트되도록 해줍니다.
장점: * 가장 깔끔하고 '개발 환경'에 최적화된 방식입니다.
- 실제 배포 환경과 유사한 테스트 경험을 제공합니다.
(빌드 툴이 중간에서 처리해주니까요.) 단점 및 주의점: * 프론트엔드 빌드 툴의 설정 파일에 의존합니다.
- 백엔드 API 자체가 이 프록시 설정을 받지 못하는 경우(예: 특정 인증 헤더가 누락되는 경우)는 별도로 백엔드에서 처리를 해주어야 할 수 있습니다.
--- ### 2.
백엔드 서버 자체에서 해결하는 방법: CORS 미들웨어 사용 (가장 확실하지만 오버헤드 발생) 질문자님이 '에러 발생률' 자체를 낮추고 싶다고 하셨으니, 서버 레벨에서 해결하는 것이 가장 근본적입니다.
원리: 백엔드 서버(Spring Boot, Express.js 등)에 CORS 관련 미들웨어(Interceptor 또는 Middleware)를 걸어서, 들어오는 모든 요청 헤더를 검사하고, 응답 헤더에 Access-Control-Allow-Origin, Access-Control-Allow-Methods 등을 명시적으로 포함시켜주는 겁니다.
구체적인 구현 예시 (프레임워크별): * Spring Boot (Java): @CrossOrigin 애너테이션을 컨트롤러나 메소드 레벨에 붙이거나, WebMvcConfigurer를 통해 전역 설정을 합니다.
} ``` * **Express.js (Node.js):** `cors` 미들웨어를 사용하고, 개발 시에는 `origin: '*'` 로 설정합니다.
```javascript const express = require('express'); const cors = require('cors'); const app = express(); app.use(cors({ origin: '*' })); // 모든 출처 허용 ``` **장점:** * 가장 근본적인 해결책입니다.
브라우저 레벨에서 오류가 나는 것이 아니라, 서버가 "너희들 와도 돼!"라고 응답 헤더로 알려주는 것이기 때문에, 테스트 환경에서 가장 확실하게 작동합니다.
**단점 및 치명적인 주의점 (⭐가장 중요⭐):** * **보안 위험:** `Access-Control-Allow-Origin: *` 를 설정하는 것은 **'누구나 접근 가능하게 한다'**는 의미입니다.
테스트 목적으로만 사용하고, 실제 운영 환경에서는 반드시 프론트엔드 주소(예: `https://my-frontend.com`)만 명시적으로 지정해야 합니다.
* **과도한 허용:** 만약 모든 요청을 막지 않고, 테스트 시마다 필요한 헤더(예: `Authorization` 같은 커스텀 헤더)까지 모두 허용하도록 설정해야 한다면, 설정이 복잡해지고 실수할 여지가 많아집니다.
--- ### 3.
테스트 목적으로만 사용하는 임시방편 (브라우저/개발자 도구 활용) 만약 위의 설정들이 너무 복잡하거나, 당장 서버 설정을 건드릴 수 없는 상황이라면, **브라우저 자체의 설정을 건드리는 방법**이 있습니다.
(이건 정말 최후의 수단입니다.) **A.
브라우저 확장 프로그램 사용:** * 'CORS Everywhere' 같은 종류의 확장 프로그램들이 존재합니다.
* 이들은 브라우저가 보내는 요청이나 받은 응답에 특정 헤더를 강제로 추가해주거나, CORS 검증 자체를 우회하도록 도와줍니다.
* **주의:** 확장 프로그램은 신뢰성이 떨어질 수 있고, 어떤 기능이 백그라운드에서 작동하는지 알기 어렵습니다.
디버깅용으로는 좋지만, 개발 습관으로 삼기엔 위험합니다.
**B.
개발자 도구에서 요청 가로채기 (Proxy 요청):** * Postman이나 Insomnia 같은 전문 API 테스트 툴을 사용하면, 브라우저를 거치지 않기 때문에 CORS 문제가 **발생하지 않습니다.** * 이 툴들은 HTTP 클라이언트의 역할을 직접 하기 때문에, 브라우저의 보안 정책(Same-Origin Policy)의 제약을 받지 않습니다.
* **추천:** 만약 '브라우저를 켜지 않고' 순수하게 API의 데이터만 테스트하고 싶다면, **Postman이나 VS Code의 REST Client 확장 기능**을 사용하시는 게 가장 '에러 발생률'이 낮습니다.
--- ### ✨ 종합 정리 및 추천 가이드라인 ✨ 질문자님의 니즈가 **"개발 흐름을 끊지 않고, 에러 발생률이 가장 낮은 방법"** 이므로, 저는 다음과 같은 순서로 시도해 보시길 권장합니다.
1.
**최우선 시도 (가장 깔끔함):** 사용 중인 프론트엔드 빌드 툴(Vite/Webpack 등)의 **프록시 설정(`proxy` 또는 `server.proxy`)**을 올바르게 적용하는 것이 1순위입니다.
이게 가장 '개발자답고' 효율적인 방법입니다.
2.
**차선책 (가장 확실함):** 만약 프록시 설정이 불가능하거나 복잡하다면, **Postman/Insomnia 같은 전문 클라이언트 툴**을 사용하여 API 호출을 테스트하는 것으로 테스트 영역을 분리하는 것이 좋습니다.
(프론트엔드 연동 테스트는 제외하고, API 기능 검증만 할 때) 3.
**최후의 수단 (백엔드 수정 필요):** 위 두 가지가 불가능하고, 정말 브라우저에서만 테스트해야 한다면, **백엔드 서버에 CORS 미들웨어를 설정**하고 `origins: *`로 임시 허용 후, 테스트가 끝나면 즉시 주소로 제한하는 것을 잊지 마세요.
**⚠️ 실무 팁 및 흔한 실수:** * **헤더 문제:** CORS 에러는 단순히 도메인 문제 외에, **요청에 포함된 커스텀 헤더(예: `X-Auth-Token`)**가 서버에서 예상하지 못하거나, 서버가 해당 헤더를 허용하지 않아도 발생할 수 있습니다.
이 경우, 백엔드에서 `Access-Control-Allow-Headers`에도 해당 헤더 이름을 명시해주어야 합니다.
* **HTTP vs HTTPS:** 테스트 환경이 로컬이더라도, 프로덕션 환경에서는 HTTPS가 기본입니다.
만약 백엔드에서 SSL 설정이 꼬이거나, 테스트 환경에서 HTTP만 허용하고 HTTPS는 차단하는 부분이 있다면 이것도 CORS처럼 느껴질 수 있습니다.
* **Preflight Request (OPTIONS):** 만약 POST/PUT 같은 요청에 '특정 헤더'가 포함되어 있다면, 브라우저는 실제 요청을 보내기 전에 **`OPTIONS` 메소드**를 먼저 보내는 '사전 요청(Preflight Request)'을 보냅니다.
CORS 에러가 날 때, 이 OPTIONS 요청 단계에서 막히는 경우가 매우 흔합니다.
이 경우 백엔드에서 OPTIONS 요청 자체를 받아들이고 적절히 응답해주는 처리가 반드시 필요합니다.
이 설명이 질문자님의 테스트 환경 구축에 도움이 되었으면 좋겠습니다.
개발하다 보면 이런 사소하지만 골치 아픈 부분들이 쌓여서 큰 스트레스가 되니까, 테스트 환경 설정은 초기에 한 번에 확실하게 잡아두는 게 정신 건강에 이롭습니다!