FastAPI: CORS 문제 해결

문제 상황

프론트(https://aaa/bbb)에서 서버로 POST 요청을 보냈다. 그런데 아래 메시지를 받았다.

🚨 Access to fetch at 'https://aaa/bbb' from origin 'https://aaa' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

CORSCross Origin Resource Sharing으로 다른 origin에서 서버 리소스를 사용할 수 있도록 공유하는 기술이다. 위 문제는 CORS를 하지 못하도록 막혔다는 뜻이다.


해결 방법

CORSMiddleware

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

app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://aaa", "https://bbb"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)
  • add_middleware를 이용해 CORS를 허용한다.
  • allow_origins에 허용할 origin을 입력한다.
  • *는 모든 요청을 허용한다.

위 예시는 origin이 https://aaahttps://bbb인 요청만 허용한다.

Origin

URL은 프로토콜, 도메인, 포트 등으로 이루어져 있다.

https://my-domain.com:8000/user/page
  • https:: 프로토콜
  • my-domain.com: 도메인

여기서 프로토콜과 도메인을 합친 부분이 origin이다. 위 예시의 경우, https://my-domain.com이  된다. 

같은 Origin

allow_origins=["https://aaa.com"]
  • https://aaa.com
  • https://www.aaa.com
  • https://www.aaa.com/path
  • https://www.aaa.com/path?q=33

위 URL에서 접근한 요청은 정상적으로 처리된다.

다른 Origin

allow_origins=["https://aaa.com"]
  • http://aaa.com
  • https://bbb.com
  • https://aaa.com:3000

위 URL은 접근이 허용되지 않는다. 참고로 allow_origins을 https://aaa.com/으로 작성하면 https://aaa.com에서 접근이 되지 않는다. 생각 없이 적은 / 때문에 한참 헤맸다.


에러 메시지를 보면 no-cors 모드를 사용하라는 부분이 있다. 

const result = await fetch('...', {
  method: 'POST',
  mode: 'no-cors',
  headers: {...},
  body: {...},
});

이 방식은 응답을 받아 올 수는 있지만, 비어있는 응답을 받게 된다. 즉, 정상적인 요청-응답이 아니니 주의해야 한다.