A A
CORS Error ํ•ด๊ฒฐํ•˜๊ธฐ: FastAPI์™€ ํ”„๋ก ํŠธ์—”๋“œ ์—ฐ๋™ ์‹œ ๋ฐœ์ƒํ•œ ์ด์Šˆ์™€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•
์š”์ฆ˜ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋ฉด์„œ FastAPI Router๋ฅผ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ์ƒ๊ธด Trouble Shooting์— ๋ฐํ•˜์—ฌ ํ•œ๋ฒˆ ์ ์–ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

FastAPI์™€ Swagger๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ VLM ์˜์ƒ ์ฒ˜๋ฆฌ ์„œ๋ฒ„๋ฅผ ๊ฐœ๋ฐœํ•˜๊ณ , ์ด๋ฅผ AWS EC2์— ๋ฐฐํฌํ•˜์—ฌ Docker ์ด๋ฏธ์ง€๋กœ ๋นŒ๋“œํ•˜๊ณ  ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์ž์ฒด๋Š” ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ–ˆ์ง€๋งŒ, ํ”„๋ก ํŠธ์—”๋“œ์™€ ์—ฐ๋™ํ–ˆ์„ ๋•Œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ CORS(Cross-Origin Resource Sharing) ์—๋Ÿฌ๋ฅผ ๋งˆ์ฃผํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

์ด ๊ธ€์—์„œ๋Š” CORS ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ์›์ธ๊ณผ ์ด๋ฅผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ–ˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์šด์˜ ํ™˜๊ฒฝ์—์„œ์˜ ๋ณด์•ˆ ๊ณ ๋ ค ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ๋‹ค๋ค„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๋ธŒ๋ผ์šฐ์ €์—์„œ์˜ CORS ์—๋Ÿฌ

ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์—ฐ๊ฒฐํ•˜๋ฉด์„œ, http://localhost:5173์—์„œ FastAPI ์„œ๋ฒ„(http://43.202.66.178:8000)๋กœ API ์š”์ฒญ์„ ๋ณด๋ƒˆ์„ ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ CORS ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค:

Access to fetch at 'http://43.202.66.178:8000/api/video/receive-video/' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

์ด ์—๋Ÿฌ๋กœ ์ธํ•ด AI Server์—์„œ ํ”„๋ก ํŠธ์—”๋“œ๋ฐ ๋ฐฑ์—”๋“œ API์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†์—ˆ๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋‹ค๋ฅธ ์ถœ์ฒ˜(Origin)์—์„œ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ–ˆ์œผ๋‚˜, ์„œ๋ฒ„๊ฐ€ ์ด๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.


CORS๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

CORS(Cross-Origin Resource Sharing)๋Š” ๊ต์ฐจ ์ถœ์ฒ˜ ์ž์› ๊ณต์œ ๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ, ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ ๋„๋ฉ”์ธ ๊ฐ„์˜ ์š”์ฒญ์„ ์ œํ•œํ•˜๋Š” ์ •์ฑ…์ž…๋‹ˆ๋‹ค. ์ฆ‰, ํ•œ ๋„๋ฉ”์ธ์—์„œ ๋กœ๋“œ๋œ ์›น ํŽ˜์ด์ง€๊ฐ€ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์˜ ์ž์›์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•  ๋•Œ, ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ณด์•ˆ์„ ์œ„ํ•ด ์ด๋ฅผ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด, ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ http://localhost:5173์—์„œ ์‹คํ–‰๋˜๊ณ  ๋ฐฑ์—”๋“œ๊ฐ€ http://43.202.66.178:8000์— ์žˆ์„ ๋•Œ, ๋‘ ๋„๋ฉ”์ธ์€ ์„œ๋กœ ๋‹ค๋ฅด๋ฏ€๋กœ ๋ธŒ๋ผ์šฐ์ €๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ์š”์ฒญ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

๊ธฐ๋ณธ์ ์œผ๋กœ ์›น ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…(Same-Origin Policy)์„ ๋”ฐ๋ฅด๋ฉฐ, ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. CORS๋Š” ์ด๋Ÿฌํ•œ ์ œํ•œ์„ ์™„ํ™”ํ•˜์—ฌ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ๋ฆฌ์†Œ์Šค ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.


๋ฌธ์ œ์˜ ์›์ธ

Access to fetch at 'http://43.202.66.178:8000/api/video/receive-video/' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ฐœ์ƒํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ถ„์„ํ•ด๋ณด๋ฉด, ์„œ๋ฒ„ ์‘๋‹ต์— Access-Control-Allow-Origin ํ—ค๋”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์š”์ฒญ์„ ์ฐจ๋‹จํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์„œ๋ฒ„๊ฐ€ CORS ์ •์ฑ…์„ ์ ์ ˆํ•˜๊ฒŒ ์„ค์ •ํ•˜์ง€ ์•Š์•˜์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.


ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

FastAPI์—์„œ CORS ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด CORSMiddleware๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
CORSMiddleware๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  1. ํŠน์ • ํ”„๋ก ํŠธ์—”๋“œ URL์„ allow_origins์— ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜๊ธฐ
  2. allow_origins๋ฅผ "*"๋กœ ์„ค์ •ํ•˜์—ฌ ๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•˜๊ธฐ

์ด ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ• ์ค‘ ์ฒซ ๋ฒˆ์งธ๋Š” ๋ณด์•ˆ์ƒ ๋” ์•ˆ์ „ํ•˜์ง€๋งŒ, ๋‘ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์€ ๊ฐœ๋ฐœ ๊ณผ์ •์—์„œ ๋น ๋ฅด๊ฒŒ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1. FastAPI์˜ CORSMiddleware ์„ค์ •

FastAPI๋Š” starlette.middleware.cors.CORSMiddleware๋ฅผ ํ†ตํ•ด CORS ์„ค์ •์„ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋‹ค์Œ์€ ๋‘ ๊ฐ€์ง€ ์„ค์ • ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•: ํŠน์ • ์ถœ์ฒ˜(origin)๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ—ˆ์šฉ

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

app = FastAPI()

origins = [
    "<http://frontend-app.yourdomain.com>",
    "<http://frontend-app2.yourdomain.com:7000>"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  # ํŠน์ • ์ถœ์ฒ˜๋งŒ ํ—ˆ์šฉ
    allow_methods=["*"],    # ๋ชจ๋“  HTTP ๋ฉ”์†Œ๋“œ ํ—ˆ์šฉ
    allow_headers=["*"],    # ๋ชจ๋“  ํ—ค๋” ํ—ˆ์šฉ
    allow_credentials=True, # ์ž๊ฒฉ ์ฆ๋ช… ํ—ˆ์šฉ (ํ•„์š” ์‹œ)
)

๋‘ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•: ๋ชจ๋“  ์ถœ์ฒ˜ ํ—ˆ์šฉ

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

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],    # ๋ชจ๋“  ์ถœ์ฒ˜ ํ—ˆ์šฉ
    allow_methods=["*"],    # ๋ชจ๋“  HTTP ๋ฉ”์†Œ๋“œ ํ—ˆ์šฉ
    allow_headers=["*"],    # ๋ชจ๋“  ํ—ค๋” ํ—ˆ์šฉ
    allow_credentials=False, # ์ž๊ฒฉ ์ฆ๋ช… ๋น„ํ—ˆ์šฉ
)

์ฃผ์˜: allow_origins ๋ฅผ "*" ๋กœ ์„ค์ •ํ•˜๋ฉด allow_credentials ๋ฅผ ๋ฐ˜๋“œ์‹œ False ๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ด๋Š” ๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์š”๊ตฌํ•˜๋Š” CORS ์ •์ฑ…์— ๋”ฐ๋ฅธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

2. ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ

์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋‘ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์ธ ๋ชจ๋“  ์ถœ์ฒ˜ ํ—ˆ์šฉ์€ ํ”ผํ•˜๊ณ , ์ฒซ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์ฒ˜๋Ÿผ ์ •ํ™•ํ•œ ํ”„๋ก ํŠธ์—”๋“œ URL๋งŒ์„ allow_origins์— ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•˜๋ฉด ์˜๋„์น˜ ์•Š์€ ์ถœ์ฒ˜์—์„œ๋„ API์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด ๋ณด์•ˆ ์ทจ์•ฝ์ ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šด์˜ ํ™˜๊ฒฝ ์„ค์ • ์˜ˆ์‹œ

origins = [
    "<https://frontend-app.yourdomain.com>",
    "<https://frontend-app2.yourdomain.com>"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  # ํŠน์ • ์ถœ์ฒ˜๋งŒ ํ—ˆ์šฉ
    allow_methods=["GET", "POST", "PUT", "DELETE"],  # ํ•„์š”ํ•œ ๋ฉ”์†Œ๋“œ๋งŒ ํ—ˆ์šฉ
    allow_headers=["Content-Type", "Authorization"], # ํ•„์š”ํ•œ ํ—ค๋”๋งŒ ํ—ˆ์šฉ
    allow_credentials=True,  # ํ•„์š” ์‹œ
)


์ฝ”๋“œ ๊ตฌํ˜„

CORS ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด FastAPI์˜ CORSMiddleware๋ฅผ ์„ค์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ํ•ด๋‹น ์„ค์ •๊ณผ ๊ด€๋ จ๋œ ์˜ˆ์‹œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

CORS Middleware ์„ค์ •

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

app = FastAPI()

# ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉ
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # ๋ชจ๋“  ์ถœ์ฒ˜ ํ—ˆ์šฉ
    allow_methods=["*"],
    allow_headers=["*"],
    allow_credentials=False,  # ์ž๊ฒฉ ์ฆ๋ช… ๋น„ํ—ˆ์šฉ
)

API ์—”๋“œํฌ์ธํŠธ ๊ตฌํ˜„

from fastapi import APIRouter, UploadFile, File, HTTPException, Response
import uuid
import os
import logging

router = APIRouter()
logger = logging.getLogger(__name__)
UPLOAD_DIR = "/path/to/upload"

class UploadResponse(BaseModel):
    video_id: str
    message: str

@router.post("/receive-video/", response_model=UploadResponse)
async def receive_video_endpoint(response: Response, file: UploadFile = File(...)):
    """
    ๋น„๋””์˜ค ํŒŒ์ผ์„ ์—…๋กœ๋“œ ๋ฐ›์•„ ์ €์žฅํ•˜๊ณ , video_id๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
    """

    # ์‘๋‹ต ํ—ค๋”์— CORS ์„ค์ • ์ถ”๊ฐ€ (๋ณด์กฐ์ ์ธ ์กฐ์น˜)
    response.headers["Access-Control-Allow-Origin"] = "*"
    response.headers["Access-Control-Allow-Credentials"] = "False"

    # ์š”์ฒญ ์ˆ˜์‹  ๋กœ๊ทธ
    logger.info("receive_video_endpoint called")
    logger.info(f"Received file: {file.filename}")

    # ์ง€์›ํ•˜๋Š” ํŒŒ์ผ ํ˜•์‹ ํ™•์ธ
    ALLOWED_EXTENSIONS = {"webm", "mp4", "mov", "avi", "mkv"}
    file_extension = file.filename.split(".")[-1].lower()
    if file_extension not in ALLOWED_EXTENSIONS:
        logger.warning(f"์ง€์›ํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ ํ˜•์‹: {file_extension}")
        raise HTTPException(status_code=400, detail="์ง€์›ํ•˜์ง€ ์•Š๋Š” ํŒŒ์ผ ํ˜•์‹์ž…๋‹ˆ๋‹ค.")

    # ๊ณ ์œ ํ•œ video_id ์ƒ์„ฑ
    video_id = uuid.uuid4().hex

    # ๋น„๋””์˜ค ํŒŒ์ผ ์ €์žฅ ๊ฒฝ๋กœ ์„ค์ •
    video_filename = f"{video_id}.{file_extension}"
    file_path = os.path.join(UPLOAD_DIR, video_filename)

    # ๋น„๋””์˜ค ํŒŒ์ผ ์ €์žฅ
    try:
        with open(file_path, "wb") as buffer:
            buffer.write(await file.read())
        logger.info(f"๋น„๋””์˜ค ํŒŒ์ผ ์ €์žฅ ์™„๋ฃŒ: {file_path}")
    except Exception as e:
        logger.error(f"ํŒŒ์ผ ์ €์žฅ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}")
        raise HTTPException(status_code=500, detail=f"ํŒŒ์ผ ์ €์žฅ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}")

    return UploadResponse(
        video_id=video_id,
        message="๋น„๋””์˜ค ์—…๋กœ๋“œ ์™„๋ฃŒ. ํ”ผ๋“œ๋ฐฑ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์œผ๋ ค๋ฉด /send-feedback/{video_id} ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ˜ธ์ถœํ•˜์„ธ์š”."
    )

์ฃผ์š” ํฌ์ธํŠธ

  • CORS Middleware ์„ค์ •: ๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•˜๋„๋ก ์„ค์ •ํ•˜์˜€์œผ๋‚˜, ์ด๋Š” ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๊ณ , ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ํŠน์ • ์ถœ์ฒ˜๋งŒ ํ—ˆ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์‘๋‹ต ํ—ค๋” ์„ค์ •: response.headers๋ฅผ ํ†ตํ•ด ์ถ”๊ฐ€์ ์ธ CORS ํ—ค๋”๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ๋ฏธ๋“ค์›จ์–ด ์„ค์ •๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ถŒ์žฅ๋˜์ง€ ์•Š์œผ๋ฉฐ, ๋ฏธ๋“ค์›จ์–ด ์„ค์ •๋งŒ์œผ๋กœ ์ถฉ๋ถ„ํžˆ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํŒŒ์ผ ์—…๋กœ๋“œ ๋กœ์ง: ๋น„๋””์˜ค ํŒŒ์ผ์„ ๋ฐ›์•„ ์ง€์ •๋œ ๋””๋ ‰ํ† ๋ฆฌ์— ์ €์žฅํ•˜๊ณ , ๊ณ ์œ ํ•œ video_id๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์— ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์šด์˜ ํ™˜๊ฒฝ์—์„œ์˜ ๋ณด์•ˆ ๊ณ ๋ ค ์‚ฌํ•ญ

๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ๋Š” ๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ์ด ํŽธ๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ณด์•ˆ์— ํฐ ์œ„ํ—˜์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์™œ ๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•˜๋ฉด ์•ˆ ๋ ๊นŒ?

  • ๋ณด์•ˆ ์œ„ํ—˜ ์ฆ๊ฐ€: ๋ชจ๋“  ๋„๋ฉ”์ธ์—์„œ ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์•…์˜์ ์ธ ์‚ฌ์ดํŠธ์—์„œ ์„œ๋ฒ„๋ฅผ ์˜ค์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํฌ๋กœ์Šค ์‚ฌ์ดํŠธ ์š”์ฒญ ์œ„์กฐ(CSRF) ๊ณต๊ฒฉ ๊ฐ€๋Šฅ์„ฑ: ์ธ์ฆ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•œ API์˜ ๊ฒฝ์šฐ, ๊ณต๊ฒฉ์ž๊ฐ€ ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„์— ์ž„์˜์˜ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ฌ๋ฐ”๋ฅธ ์ ‘๊ทผ ๋ฐฉ๋ฒ•

์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ํ—ˆ์šฉํ•  ์ถœ์ฒ˜๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:

origins = [
    "<https://your-frontend-domain.com>",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,  # ํ•„์š”ํ•œ ๊ฒฝ์šฐ True๋กœ ์„ค์ •
    allow_methods=["GET", "POST"],  # ํ—ˆ์šฉํ•  HTTP ๋ฉ”์„œ๋“œ ์ œํ•œ
    allow_headers=["Content-Type", "Authorization"],  # ํ•„์š”ํ•œ ํ—ค๋”๋งŒ ํ—ˆ์šฉ
)

์ด๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๋Š” ์ง€์ •๋œ ๋„๋ฉ”์ธ์—์„œ ์˜ค๋Š” ์š”์ฒญ๋งŒ ํ—ˆ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.


์ถ”๊ฐ€์ ์ธ ๊ณ ๋ ค ์‚ฌํ•ญ: ์‘๋‹ต ํ—ค๋” ์ˆ˜๋™ ์„ค์ • ํ”ผํ•˜๊ธฐ

์ฒ˜์Œ์—๋Š” ๊ฐ ์—”๋“œํฌ์ธํŠธ์˜ ์‘๋‹ต ํ—ค๋”์— ์ง์ ‘ CORS ๊ด€๋ จ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค:

response.headers["Access-Control-Allow-Origin"] = "*"

ํ•˜์ง€๋งŒ ์ด๋Š” ๊ถŒ์žฅ๋˜์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

  • ์œ ์ง€ ๋ณด์ˆ˜ ์–ด๋ ค์›€: ๊ฐ ์—”๋“œํฌ์ธํŠธ๋งˆ๋‹ค ํ—ค๋”๋ฅผ ์ˆ˜๋™์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์ง€๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.
  • ๋ฏธ๋“ค์›จ์–ด ํ™œ์šฉ: FastAPI์˜ CORSMiddleware๋Š” CORS ์„ค์ •์„ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ, ์ฝ”๋“œ์˜ ์ผ๊ด€์„ฑ๊ณผ ์œ ์ง€ ๋ณด์ˆ˜์„ฑ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

CORS ์—๋Ÿฌ๋Š” ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ์˜ ๋„๋ฉ”์ธ์ด ๋‹ค๋ฅผ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์„œ๋ฒ„์—์„œ ์ ์ ˆํ•œ CORS ์„ค์ •์„ ํ•ด์•ผ ํ•˜๋ฉฐ, FastAPI์—์„œ๋Š” CORSMiddleware๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‰ฝ๊ฒŒ ์ด๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์š”์ 

  • ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•˜๋˜, ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฐ˜๋“œ์‹œ ํ—ˆ์šฉํ•  ์ถœ์ฒ˜๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • allow_credentials ์„ค์ •์— ์œ ์˜ํ•ด์•ผ ํ•˜๋ฉฐ, allow_origins๊ฐ€ "*"์ผ ๋•Œ๋Š” allow_credentials๋ฅผ False๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์‘๋‹ต ํ—ค๋”๋ฅผ ์ˆ˜๋™์œผ๋กœ ์„ค์ •ํ•˜๊ธฐ๋ณด๋‹ค๋Š” CORSMiddleware๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ  ์ž๋ฃŒ

 

Middleware - Starlette

Middleware Starlette includes several middleware classes for adding behavior that is applied across your entire application. These are all implemented as standard ASGI middleware classes, and can be applied either to Starlette or to any other ASGI applicat

www.starlette.io

 

 

Cross-Origin Resource Sharing (CORS) - HTTP | MDN

Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. CORS also relies on a mechanism by which

developer.mozilla.org

 

 

CORS (Cross-Origin Resource Sharing) - FastAPI

FastAPI framework, high performance, easy to learn, fast to code, ready for production

fastapi.tiangolo.com