TOP
본문 바로가기
[파이썬 Projects]/<파이썬 웹개발>

[파이썬] FastAPI - 미들웨어(middleware) - 2: CORS

by 기록자_Recordian 2025. 5. 8.
728x90
반응형
이전 내용
 

[FastAPI] 미들웨어(middleware) - 1: TrustedHostMiddleware

이전 내용 [FastAPI] 캐싱(caching)이전 내용 [FastAPI] 파일 업로드이전 내용 [FastAPI] 비동기 처리 (asynchronous processing)이전 내용 [FastAPI] 고급 인증: 세션이전 내용 [FastAPI] 고급인증: JWT이전 내용 [FastAPI]

puppy-foot-it.tistory.com


FastAPI 주요 미들웨어
2. CORS 미들웨어

 

◆ CORS(Cross-Origin Resource Sharing, 교차 출처 리소스 공유)

브라우저가 자신의 출처가 아닌 다른 어떤 출처(도메인, 스킴 혹은 포트)로부터 자원을 로딩하는 것을 허용하도록 서버가 허가 해주는 HTTP 헤더 기반 매커니즘으로, 웹 보안의 한 부분이다.

CORS는 교차 출처 리소스를 호스팅하는 서버가 실제 요청을 허가할 것인지 확인하기 위해 브라우저가 보내는 "사전 요청(Preflight)" 매커니즘에 의존하며, 이 사전 요청에서 브라우저는 실제 요청에서 사용할 HTTP 메서드와 헤더들에 대한 정보가 표시된 헤더에 담아 보낸다.

 

웹 브라우저는 웹페이지가 다른 도메인의 리소스에 접근하려고 할 때 제약을 걸어두는데, 이것을 동일 오리진 정책(same-origin policy)이라 부른다. 여러 도메인 간에 자원을 공유해야 하는 상황이 생길 때 CORS는 안전하게 자원을 공유할 수 있는 방법을 정의한다.

만약, 웹 애플리케이션 A가 도메인 a.com에, 웹 애플리케이션 B가 b.com에 있다고 가정할 때, 웹 애플리케이션 A에서 웹 애플리케이션의 B의 API를 호출하려면 도메인이 달라 보안 문제가 발생할 수 있어 이럴 때 CORS의 설정이 필요하게 된다.

 

CORS 미들웨어는 이런 교차 오리진 문제 해결을 위해 웹 서버에 추가하여 클라이언트에서 서버로 요청을 보낼 때 서버는 CORS 미들웨어를 통해 이 요청이 안전한지 판단한다.

  • CORSMiddleware 임포트.
  • 허용되는 출처(문자열 형식)의 리스트 생성.
  • FastAPI 응용 프로그램에 "미들웨어(middleware)"로 추가.

백엔드에서 다음 사항을 허용할지에 대해 설정할 수 있다.

  • 자격증명 (인증 헤더, 쿠키 등).
  • 특정한 HTTP 메소드(POST, PUT) 또는 와일드카드 "*" 를 사용한 모든 HTTP 메소드.
  • 특정한 HTTP 헤더 또는 와일드카드 "*" 를 사용한 모든 HTTP 헤더.

CORSMiddleware 기본 매개변수

 

CORSMiddleware 에서 사용하는 기본 매개변수는 제한적이므로, 브라우저가 교차-도메인 상황에서 특정한 출처, 메소드, 헤더 등을 사용할 수 있도록 하려면 이들을 명시적으로 허용해야 한다.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"], # 어떤 오리진의 요청을 받을 것인지 설정
    allow_credentials=True, # 자격 증명 포함한 요청 허용 여부 설정
    allow_methods=["*"], # 허용할 HTTP 메서드 설정
    allow_headers=["*"], # 허용할 HTTP 헤더 설정
)

@app.get("/")
def read_root():
    return {"message": "CORS 테스트"}

@app.get("/hello")
def hello():
    return {"message": "안녕하세요!"}
  • allow_origins: 웹사이트의 오리진별로 특정 요청을 허용하거나 거부 할 수 있다. ▶ 어떤 도메인에서의 요청을 허용할지 설정. 예) ['https://example.org', 'https://www.example.org']. 모든 출처를 허용하기 위해 ['*'] 를 사용할 수 있다.
  • allow_origin_regex: 교차-출처 요청을 보낼 수 있는 출처를 정규표현식 문자열로 나타낸다. 'https://.*\.example\.org'.
  • allow_methods: 교차-출처 요청을 허용하는 HTTP 메소드의 리스트로 허용할 HTTP 메서드를 설정하며, 기본값은 ['GET'] . ['*'] 을 사용하여 모든 표준 메소드들을 허용할 수 있다.
  • allow_headers: 교차-출처를 지원하는 HTTP 요청 헤더의 리스트로 어떤 HTTP 헤더를 허용할 것인지 설정하며, 기본값은 []. 모든 헤더들을 허용하기 위해 ['*'] 를 사용할 수 있다. Accept, Accept-Language, Content-Language 그리고 Content-Type 헤더는 코르스 요청시 언제나 허용된다.
  • allow_credentials: 교차-출처 요청시 자격 증명 (쿠키, HTTP 인증 등) 지원 여부를 설정하며, 기본값은 False. 또한 해당 항목을 허용할 경우 allow_origins 는 ['*'] 로 설정할 수 없으며, 출처를 반드시 특정해야 한다. 자격 증명은 사용자가 누구인지 확인할 수 있는 정보.
  • expose_headers: 브라우저에 접근할 수 있어야 하는 모든 응답 헤더를 가리키며, 기본값은 [].
  • max_age: 브라우저가 코르스 응답을 캐시에 저장하는 최대 시간을 초 단위로 설정하며, 기본값은 600.
- HTTP Authentication: 웹에서 사용자 인증을 하기 위한 방법 중 하나로, 사용자 이름과 비밀번호를 기반으로 하는 기본 인증(basic authentication)이나 토큰 기반의 베어러(bearer) 인증 등 다양한 방식이 있다.

- Authorization 헤더: 주로 토큰을 퐇마하여 서버에 보내서 사용자를 인증

- Content-Type 헤더: 요청의 바디 타입을 명시하는 것으로, 서버에 어떤 형태의 데이터를 보내는지 알려주는 표시다. ex) JSON 데이터: "application/json"

CORS 테스트 1

 

main.py를 실행하여 서버를 실행시키고 해당 파일이 들어있는 폴더에 index.html 파일을 만들고 코드를 작성한다.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>CORS 테스트</title>
    <meta charset="UTF-8"> <!-- UTF-8 설정 추가-->
    <script type="text/javascript">
        async function makeRequest() {
            try {
                const response = await fetch('http://localhost:8000/hello', 
                    {
                        method: 'GET',
                        credentials: 'include'
                    });

                    if (!response.ok) {
                        throw new Error("Network response was not ok");
                    }

                    const data = await response.json();
                    console.log(data);
                    document.getElementById("result").innerHTML = JSON.stringify(data);
                } catch (error) {
                    console.error("There was a problem with the fetch operation:", error);
                    document.getElementById("result").innerHTML = "Error occured: " + error;
                }
            }
    </script>
</head>
<body>
    <h1>CORS 테스트 페이지</h1>
    <button onclick="makeRequest()">요청 보내기</button>
    <div id="result"> 결과가 여기 표시됩니다.</div>
</body>
</html>

 

[테스트]

main.py 서버가 실행된 상태에서 다른 터미널을 열고 아래 코드를 실행한다.

python -m http.server 8080

 

그리고 웹 페이지에서 [요청 보내기] 버튼을 클릭하여

CORS가 정상 동작했다면 화면에 {"message": "안녕하세요!"} 가 뜬다.

※ 왜 python -m http.server 8080인가?
python -m http.server 8080 명령은 **HTML, CSS, JS 같은 정적 파일(프론트엔드)**을 브라우저에서 쉽게 열 수 있게 해주는 간단한 웹 서버를 여는 명령이다.
보통 백엔드 서버(FastAPI)는 8000 포트를 많이 사용
프론트엔드 테스트용 정적 서버는 8080 포트를 많이 사용
▶ 즉, 두 서버가 필요하다.

용도 명령어 포트 설명
백엔드 API uvicorn main:app --reload --port 8000 8000 FastAPI 서버 (API 응답 담당)
프론트엔드 python -m http.server 8080 8080 정적 HTML 제공 (index.html)
8000 포트는 보통 FastAPI 백엔드에서 이미 사용하고 있으므로, 같은 포트를 두 프로세스가 동시에 사용할 수 없다. 그래서 정적 파일용 웹서버는 8080이나 3000, 5500 같은 포트를 사용한다.

CORS 테스트 2

 

이번에는 allow_origins를 일부 도메인에서의 요청에 대해서만 동작하도록 변경하고, main.py 파일을 재실행한다.

index.html 파일은 재실행할 필요 없이 그대로 있어도 된다.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com", "https://*.example.com"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
def read_root():
    return {"message": "CORS 테스트"}

@app.get("/hello")
def hello():
    return {"message": "안녕하세요!"}

 

웹페이지에서 [요청 보내기]를 클릭하면 'Error occurred: TypeError: Failed to fetch' 라는 에러 메시지가 표시된다.

 

이는 "https://example.com", "https://*.example.com" 같은 주소를 가진 요청만 정상 요청으로 받기 때문이다.


[참고]

가장 빠른 풀스택을 위한 플라스크 & FastAPI
https://developer.mozilla.org/ko/docs/Web/HTTP/Guides/CORS
https://fastapi.tiangolo.com/ko/tutorial/cors/?h=cors#corsmiddleware


다음 내용

 

[FastAPI] 미들웨어(middleware) - 3: GZip

이전 내용 [FastAPI] 미들웨어(middleware) - 2: CORS이전 내용 [FastAPI] 미들웨어(middleware) - 1: TrustedHostMiddleware이전 내용 [FastAPI] 캐싱(caching)이전 내용 [FastAPI] 파일 업로드이전 내용 [FastAPI] 비동기 처리 (as

puppy-foot-it.tistory.com

 

728x90
반응형