로고 라이트 모드

[Vite·React] Proxy 설정으로 CORS 문제 해결하기 (.env 활용)

2025년 5월 31일 • 김소원 의미 없는 키위

개발 환경에서 CORS 오류를 피하기 위해 Vite의 Proxy와 환경 변수를 설정하는 방법을 정리했습니다.

***

학회 웹 페이지 퀴즈 관련 API를 연결하던 중 CORS 에러를 마주했다.

CORS 오류 메시지

… from origin ‘http://localhost:5173’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

흠…

CORS란?

그런데 사실 CORS는 에러가 아니다. 우리는 동일 출처 정책(Same Origin Policy, SOP)을 위반하고 있던 것이다. SOP는 한 Origin에서 로드된 문서나 스크립트가 다른 Origin의 리소스와 상호 작용하는 것을 제한하는 보안 메커니즘이다.

즉, 웹 브라우저의 보안을 위해 프로토콜, 호스트, 포트가 동일한 서버에서만 ajax 요청을 주고 받을 수 있도록 한 정책이다. 늘려 말하면 교차 출처 리소스 공유(Cross Origin Resource Sharing)가 된다.

URL설명
http://store.company.com:8000- 프로토콜: http
- 호스트: store.company.com
- 포트: 8000

➡️ 여기서 모두 같으면 Same Origin, 하나라도 다르면 Cross Origin이라고 한다.

CORS 이슈 해결 방법

  1. 동일 출처로 이동

    하지만 이 방법은 로컬 개발 중일 경우 어려울 수 있다.

  2. 서버에서 Access-Control-Allow-Origin 헤더 추가

    서버에서 특정 클라이언트 요청에 대한 cross-origin HTTP 요청을 허가하는 Access-Control-Allow-Origin 헤더를 추가한다. 하지만 이 방법은 보안에 취약할 수 있다.

    지금까지 나는 CORS 이슈를 무조건 이 방법으로 해결해야 하는 것으로 알고 있었다 ( ;;)

  3. Proxy

    Proxy는 API로 네트워크 요청/응답을 주고 받는 클라이언트와 서버 사이를 중개하는 역할을 한다.

    프론트엔드에서 Proxy를 이용해 우회하면, 클라이언트에서 API를 요청할 때 백엔드 서버에 직접적으로 요청하지 않고 현재 개발 서버 주소로 요청을 한다.

Vite 환경에서 Proxy 설정하기

포스트 작성 당시 나는 Vite를 활용한 개발을 진행하고 있었기 때문에 Vite를 기준으로 Proxy 우회 방법을 설명하고자 한다. (참고로 지금은 Next로 프레임워크를 Migration 했다.)

  1. vite.config.ts 에서 Proxy 경로를 설정한다.

    import { defineConfig } from 'vite'
    import react from '@vitejs/plugin-react-swc'
    
    // https://vite.dev/config/
    export default defineConfig({
        plugins: [react()],
        server: {
            proxy: {
                '/api': {
                    target: 'https://api.server.kr',
                    changeOrigin: true,
                    rewrite: (path) => path.replace(/^\/api/, ''),
                    secure: false,
                    ws: true,
                },
            },
        },
    })
    • target: /api 앞 부분인 Origin을 지정한 서버 도메인 주소로 바꾼다.
    • changeOrigin: 요청 헤더 host 필드 값을 대상 서버의 host로 변경한다.
    • rewrite: 요청 경로에서 /api를 제거한다.
    • secure: false: SSL 인증서 검증을 무시한다.
    • ws: true: WebSocket 프로토콜을 사용한다.
  2. env 이용해서 Proxy 설정하기

    target에 도메인을 직접 지정해도 되지만 env 환경 변수를 사용할 수 있다. config 파일에서는 import.meta.env.VITE_… 이런 식으로 환경 변수를 가져올 수 없으므로 loadEnv를 import해 사용해야 한다.

    import { defineConfig, loadEnv } from 'vite'
    import react from '@vitejs/plugin-react-swc'
    
    // https://vite.dev/config/
    export default ({ mode }: { mode: string }) => {
        const env = loadEnv(mode, process.cwd())
    
        return defineConfig({
            plugins: [react()],
            server: {
                proxy: {
                    '/api': {
                        target: env.VITE_SERVER_API_URL,
                        changeOrigin: true,
                        rewrite: (path) => path.replace(/^\/api/, ''),
                        secure: false,
                        ws: true,
                    },
                },
            },
        })
    }
  3. Proxy 설정한 URL에 맞게 API를 호출한다.

    const response = await axios.get(`/api/quiz/verification?${params}`)

덕분에 문제를 해결했다!

CORS 오류 해결!

***