ReactやVue.jsなどを使ってイケてるフロントエンドUIを作り、「いざ、バックエンドのPython API(FastAPI/Flask) に接続してデータを取得だ!」と気合を入れてブラウザをリロードした瞬間。
コンソール画面に赤裸々に叩きつけられる、Web開発者全員の登竜門であり、一生涯の宿敵となるエラーメッセージがこちらです。
Access to fetch at 'http://localhost:8000/api' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource...
「いやいやいや!自分のPCの中で、自分自身が作ったAPIを呼んでいるだけなのになぜ怒られるの!?」
フロントエンドの初心者層が最も発狂しやすいこのエラー。実はこれ、APIやバックエンド側のバグではなく、「ブラウザ(ChromeやSafari)が持つ極めて厳重なセキュリティ機関」による親切な機能なのです。
本記事では、この魔法の言葉「CORS」の正体を暴き、セキュリティを確保したままフロントエンドと通信させる設定の真髄を解説します!
1. すべての元凶「同一生成元ポリシー (Same-Origin Policy)」
あなたが銀行のサイトにログインしている状態で、裏で悪意のある別サイトを開いてしまったとします。
もしブラウザに何のリミッターも無かったら、この悪意あるサイトに仕込まれたJavaScriptが、あなたのブラウザに保存された銀行のログイン情報を勝手に使い、「銀行APIに向けて勝手に送金リクエストを飛ばす(通信させる)」ことができてしまいます。
これを防ぐため、現代のブラウザは「同一生成元ポリシー(SOP: Same-Origin Policy)」という絶対のルールを内蔵しています。
「https://evil.com というドメインの画面からは、https://bank.com という別のドメインのAPIへの通信は、問答無用でブロックして弾く!」という、門番の役割です。
今回のエラーの原因もこれです。
フロント側(React)は「ポート3000番(localhost:3000)」から動いており、バックエンド側(Python)は「ポート8000番(localhost:8000)」に乗っています。
ブラウザにとって、ポート番号が違うだけでも「あ!これは別の生成元(ドメイン)からの怪しい通信だ!」と判断され、容赦なく遮断されてしまうのです。
2. 「CORS」はエラーではなく、特例の「通行許可証」
CORS(Cross-Origin Resource Sharing)とは、上記のような厳格なルールに対して、
「このサイトからの通信だけは特別に安全だと認めるから、通して良いよ!」
という特例許可をブラウザに宣言するための『通行許可証の仕組み』のことです。
つまり、「CORSエラー」という言葉自体が表現として少しおかしいのです。
正しくは、「ブラウザのセキュリティによってブロックされたが、それを解除するためのCORSの通行許可証(ヘッダー情報)が見つからなかったよ」というエラーなのです。
3. バックエンドで通行許可証を発行(実装)する
このエラーを解決するためには、フロントエンド側(Reactなど)で頑張って設定をこねくり回しても意味がありません。(フロント側で抜け穴を作れたら、セキュリティの意味がないからです。)
解決のカギは、バックエンド側(APIサーバー側)が「レスポンスヘッダ」に許可証を添付して返すことです。
モダンなPythonフレームワークである「FastAPI」を例に、数分で実装できる完璧なCORS対応コードを見てみましょう。
from fastapi import FastAPI
# CORS対応のための専用ミドルウェアをインポート
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# 1. 通信を許可したい「フロントエンドのURL」をリストで指定する(特例許可リスト)
# ※本番環境では https://my-cool-app.com 等を指定します
origins = [
"http://localhost:3000",
"http://127.0.0.1:3000",
]
# 2. アプリケーションに門番(ミドルウェア)として追加する
app.add_middleware(
CORSMiddleware,
allow_origins=origins, # 上で定義したURLからの通信のみを許可!
allow_credentials=True, # Cookieなどの認証情報のやり取りも許可
allow_methods=["*"], # GET, POST, PUT, DELETE などすべてのメソッドを許可
allow_headers=["*"], # カスタムヘッダーなどもすべて許可
)
@app.get("/api/data")
def read_data():
return {"message": "CORSの壁を越えて、無事にデータが届きました!"}この設定を追加するだけで、APIサーバーの返却データに Access-Control-Allow-Origin: http://localhost:3000 という魔法のヘッダー(特例許可証)が自動でくっつくようになります。
これを見たブラウザは「おっ、APIサーバー本人が『localhost:3000からのアクセスなら歓迎する』と言っているな。よし、通してやろう!」と判断し、エラーが綺麗に消滅するのです。
まとめ:ネットワークの仕様はWeb開発の心臓
CORSエラーに遭遇すると「もう嫌だ、Web開発は面倒だ」と発狂しそうになりますが、実はその背後には『世界中のユーザーを悪意ある攻撃から守るための、ブラウザの愛と防壁』が隠されています。
フロントエンドからバックエンドへと技術の幅を広げていくと、CORSやCookie、HTTP通信のメソッド(Options通信など)の深い理解が必ず求められるフェーズがやってきます。「なんか通ったからいいや」ではなく、ネットワークセキュリティの基本を専門書などで一度しっかり腰を据えて学ぶことで、どんなエラーでも恐れないフルスタックエンジニアへの道が開けるでしょう。


コメント