FastAPI를 배워보자 13일차 - Middleware, CORS

0

fastapi

목록 보기
13/13

https://fastapi.tiangolo.com/tutorial/middleware/

Middleware

middleware는 handler의 앞, 뒤로 실행되는 handler로 다음과 같이 실행이 가능하다.

client --request--> Middleware --request--> Handler --response--> Middleware --resonse--> client

물론 handler 앞 뒤로 모두 middleware가 동작하게 할 수 있고, request받을 때만 동작, response받을 때만 동작하게도 할 수 있다.

사실 MiddlewareDepends로 해결이 가능하며, 실제로 fastapi에서는 middleware를 쓰는 것보다 Depends를 쓰는 것을 권장한다. 왜냐하면 fastapi에서 제공하는 middleware는 매우 빈약하기 때문이다.

import time

from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response

middleware를 만들기 위해서는 @app.middleware('http') decorator를 function위에 만들어주면 된다. middleware decorator를 사용하는 함수에는 2가지 인자가 들어오는데, 하나는 client로부터 오는 request parameter이고 다른 하나는 call_next로 middleware다음에 실행될 handler이다. 따라서 requestcall_next에 전달해주어야한다.

또한, middleware 함수는 call_next에게서 response를 받고, 원하는 처리 이후에 client에게 Response를 보낼 수 있다.

위의 code는 middleware로 감싸진 handler인 call_next가 실행되는 시간을 측정하고 마지막에 응답을 전송할 때 header를 추가하고 전송하는 것이다.

중요한게 있는데 fastapi에서는 http로 요청이 오는 모든 handler에 대해서 위의 middleware가 적용된다는 것이다. custom하게 설정하는 방법이 있긴하지만 개별적으로 middleware를 각각 적용하지 못한다. 따라서, middleware보다는 동작이 비슷하지만 더 편하고 다양하게 사용할 수 있는 Dependency를 사용하는 것을 추천한다.

CORS(Cross-Origin Resource Sharing)

CORS(cross-origin resource sharing)은 frontend와 backend의 'origin'이 서로 다른 경우에 발생하는 상황을 말한다. https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

Origin이란 protocol(http, https) + domain(myapp.com, localhost.com) + port(80, 443)의 조합을 말한다. 따라서 같은 localhost라도 httphttps에 따라서도 다르고 port번호에 따라서도 달라진다.

http://localhost:8080에 동작하고 있는 fronted app이 있다고 하자. 해당 app은 backend인 http://localhost에 요청을 보내려고 한다. browser에서는 CORS를 위해서 frontend의 request보다 먼저 HTTP OPIONS 요청을 backend로 먼저 보내는데, 여기서 통신에 성공하기 위한 적절한 header와 규약이 있어야, frontend의 request가 backend로 전달된다.

이러한 동작을 CORS preflight requests라고 한다. OriginAccess-Control-Request-Method header를 가진 OPTIONS requests를 전달한다. fastapi에서는 middleware module을 제공하여 preflight요청이 오면 적절한 CORS header와 함께 응답을 전송한다.

이를 위해서 backend에서는 allowed origins list를 가져야하고, 해당 list에 frontend주소인 http://localhodt:8080가 명시되어있어야 한다.

fastapi에서는 CORSMiddleware를 사용해서 CORS문제를 해결할 수 있다. CORSMiddleware에 허용할 origin list들과 어떤 http method, header를 허용할 지 지정할 수 있다.

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

app = FastAPI()

origins = [
    "http://localhost.tiangolo.com",
    "https://localhost.tiangolo.com",
    "http://localhost",
    "http://localhost:8080",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.get("/")
async def main():
    return {"message": "Hello World"}
  1. allow_origins: origin의 list로 cross-origin 요청들을 허용한다. 가령 ['*']으로 적으면 모든 orign을 허용하고 ["https://example.org"]https://example.org에서만 오는 request만 받는다.
  2. allow_origin_regex: regex string으로 origin을 표현한 것이다. 'https://.*\.example\.org'와 같은 것들이 가능하다.
  3. allow_methods: cross-origin request에 대해서 허용되는 HTTP method들을 지정한다. 기본적으로 ['GET]이 default이고 ['*']으로 적으면 모두 가능하다.
  4. allow_headers: cross-origin request를 위해 지원되어야할 HTTP request header의 list이다. default로 []이고 모든 header를 받기 위해서 ['*']도 가능하다. simple CORS request에 대해서는 Accept, Accept-Language, Content-Language, Content-Type이 항상 허용된다.
  5. allow_credentials: cross-orign request를 위해 지원되어야할 cookie들을 지정한다. 기본적으로 False이다. 또한 credential이 허용된다면 allow_origins['*']로 설정될 수가 없고, 반드시 origin을 명시해야한다.
  6. expose_headers: 브라우저에 접근 가능하도록 만들어야하는 response header를 지정한다. default는 []이다.
  7. max_age: 브라우저에서 CORS 응답들을 캐싱하기 위한 seconds를 지정한다. default로 600이다.

정리하면 다음과 같다.

       | ---preflight request(OPTIONS) --->    |
client | <-- CORS response with header(origin) | server
       | ---actual request(GET, POST ...) ---> |
       | <-- actual response               --- |

우리가 설정한 middleware는 preflight가 오고 CORS response를 보낼 때 필요한 origin, credential 여부 등의 header를 설정하고 응답을 보내는 것이다.

0개의 댓글

관련 채용 정보