Starlette 와 FastAPI 의 ISSUE(link,link) 에서는 다음의 해결법이 논의 되었습니다.
논의된 해결법
1. FastAPI 앱을 CORSMiddleware로 감싸기
from: thomasleveil
from starlette.applications import Starlette
from starlette.authentication import AuthenticationBackend, AuthenticationError
from starlette.exceptions import HTTPException
from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import JSONResponse
import uvicorn
class DumbAuthBackend(AuthenticationBackend):
async def authenticate(self, request):
raise AuthenticationError("You will never be authenticated!")
app = Starlette(debug=True)
# Global authentication
app.add_middleware(AuthenticationMiddleware, backend=DumbAuthBackend())
@app.route('/')
async def index(request):
return JSONResponse({"hello": "world"})
if __name__ == '__main__':
uvicorn.run(
CORSMiddleware(app=app, allow_origins=["*"]),
host='0.0.0.0',
port=8000
)
CORSMiddleware가 자체적으로 ASGI 앱이므로 FastAPI 앱을 감싸도록 구성합니다. 이를 통해 outermost middleware 가 CORSMiddleware 가 되기 때문에 CORS 헤더 문제를 자연스럽게 해결하게 됩니다.
평가
- ✅ 장점: 비교적 간단하게 적용 가능
- ⚠️ 단점: 초보자에게는 이러한 wrapping 개념이 이해하기 어려울 수 있습니다.
이렇게 문제를 해결하는 것은 Starlette App 구성이 갖는 문제를 또다른 ASGI App 을 만들어서 해결하는 것으로 뭔가 와닿지 않습니다.
차라리 Starlette 측에서 CORSMiddleware 를 추가하는 새로운 방법을 제공하는게 맞을 것입니다.
2. ExceptionHandler에서 직접 CORS 헤더 추가
from: ddahan
def add_cors(request: Request, response: JSONResponse) -> JSONResponse:
"""
CORS headers are not automatically added to error handlers with FastAPI
cf. https://github.com/fastapi/fastapi/discussions/8027
"""
cors_headers = {
"Access-Control-Allow-Methods": ", ".join(settings.CORS_ALLOW_METHODS),
"Access-Control-Allow-Headers": ", ".join(settings.CORS_ALLOW_HEADERS),
"Access-Control-Allow-Credentials": str(settings.CORS_ALLOW_CREDENTIALS).lower(),
}
# If the origin is in the allowed list, add it to the CORS headers
origin = request.headers.get("origin")
if origin in settings.CORS_ALLOW_ORIGIN:
cors_headers["Access-Control-Allow-Origin"] = origin
response.headers.update(cors_headers)
return response
def internal_exception_handler(request: Request, exc: Exception) -> JSONResponse:
response = JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={
"errors": {
"general": [
"An unknown error has occurred. Please contact an administrator."
]
}
},
)
return add_cors(request, response)
settings 로 CORS 관련 세팅을 전역적으로 관리하려고 하는 시도가 돋보입니다.
ExceptionHandler 는 ServerErrorMiddleware 와 ExceptionMiddleware 에 적용되기 때문에 CORSMiddleware 를 우회하여 반환되는 이유로 CORS 헤더가 누락되는 문제를 해결할 수 있습니다.
평가
- ✅ 장점: 원하는 예외 상황에서 정확하게 CORS 헤더를 제어할 수 있습니다.
- ⚠️ 단점: 전역적으로 처리해야 할 CORS 헤더를 개별 ExceptionHandler에서 설정하는 것은 비효율적이며 비표준적입니다.
비록 CORS 관련 세팅을 전역적으로 처리하려고 했으나 본질적으로 예외 처리 시 응답에 CORS 헤더를 수동으로 추가하는 것입니다. CORS에 처리는 Applciation 전역적으로 처리되어야 하는데, 지엽적인 처리에 머물러 있는것 같아 아쉽습니다.
결론
지극히 개인적인 의견입니다.
CORS Middleware 로 FastAPI application 을 감싸는 행위는 이해하기 어려습니다. 과연 라이브러리 수준에서 정식으로 권장하는 문제라고 받아들일 수 있을까요?
또한 ExceptionHandler 에서 직접 header 를 추가하는것도 이상합니다. 일부 경우를 제외하고 CORS 에 대한 대응은 application 전역적인 처리가 되어야 하기 때문입니다.
제 3의 해법이 필요해 보입니다, 그리고 이 문제를 해결하는 과정은 "FastAPI ErrorHandling 과 CORS (3) - 문제 해결" 에 정리했습니다.
'탐구 생활 > FastAPI CORS' 카테고리의 다른 글
FastAPI ErrorHandling 과 CORS (3) - 문제 해결 (0) | 2025.02.22 |
---|---|
FastAPI ErrorHandling 과 CORS (1) - 문제 파악 (0) | 2025.02.10 |