📘

CORSとPreflightリクエスト

2024/10/30に公開

はじめに

フロントエンドとバックエンド間でAPI通信を行う際、ブラウザのセキュリティ制限によりCORS(Cross-Origin Resource Sharing:クロスオリジンリソース共有)エラーが発生することがあります。本記事では、CORSの仕組みやPreflightリクエストの動作について解説し、エラーが発生した場合の解決方法を紹介します。

この記事の対象読者

この記事は、以下のようなエンジニアや開発者を対象としています。

  • フロントエンドとバックエンドを連携させたAPI通信を行う際に、CORSエラーに直面した方
  • ReactやVueなどのSPAからAPIを呼び出す開発をしている方
  • バックエンドにFlaskやExpressを使用しており、CORSの設定に不慣れな方
  • Preflightリクエストが原因のエラーに対する理解を深めたい方

CORSは、初学者から経験者まで頻繁に悩むポイントなので、正しく理解し、トラブルシューティングできるようになることを目指しています。

CORS(クロスオリジンリソース共有)とは?

CORSは、ブラウザが異なるオリジン(例:http://localhost:3000からhttp://127.0.0.1:5000)へのリクエストを送る場合に、セキュリティ上の理由でリクエストを制限する仕組みです。CORSは、サーバーが許可する場合に限り、クライアントからのリクエストを受け入れます。

Preflightリクエストとは?

Preflightリクエストは、ブラウザが本体のリクエストを送信する前に、サーバーがそのリクエストを受け入れるかどうかを確認するためのOPTIONSリクエストです

  • Preflightリクエストの特徴
    • HTTPメソッドがOPTIONS
    • 本体のリクエストに先行して送信される
    • サーバーがCORSの許可を示す必要がある

Preflightリクエストが発生する条件

  • リクエストにカスタムヘッダー(例:Authorization)が含まれている場合
  • HTTPメソッドがPOST, PUT, DELETEなど、単純なリクエスト以外の場合
  • リクエストヘッダーにContent-Type: application/jsonが含まれている場合

CORSエラーの発生原因と解決方法

  1. FlaskでのCORS設定
    PythonのFlaskでAPIを実装する場合、CORSの設定が不十分だとPreflightリクエストが失敗します。flask-corsを使うことで、簡単にCORSを許可できます。

flask-corsのインストール

pip install flask-cors

FlaskアプリにCORSを設定する

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # すべてのオリジンを許可

@app.route('/login', methods=['POST'])
def login():
    return {"message": "Login successful"}
  1. 特定のオリジンを許可する方法
    すべてのオリジンを許可するのではなく、特定のオリジンだけを許可したい場合は、次のように設定します。
CORS(app, resources={r"/*": {"origins": "http://localhost:3000"}})
  1. 必要なCORSヘッダーの例
    Preflightリクエストが成功し、本体リクエストが実行されるためには、次のようなヘッダーが必要です。
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
  1. Preflightと本体リクエストの確認方法
    1. ブラウザのDevTools(F12)を開き、Networkタブでリクエストを確認します。
    2. OPTIONSリクエストが200 OKを返していれば、Preflightは正常に動作しています。
    3. 本体リクエスト(例:POST /login)がブロックされずに実行されているか確認します。
  2. ReactからのAPIリクエスト例
    以下は、ReactからFlask APIにPOSTリクエストを送る際のサンプルコードです。
import axios from 'axios';

const API_URL = 'http://127.0.0.1:5000';

export const login = async (username: string, password: string) => {
  const response = await axios.post(`${API_URL}/login`, { username, password });
  return response.data.token;
};
  1. まとめ
    CORSとPreflightリクエストは、Webアプリケーションのセキュリティを強化するための重要な仕組みです。適切に設定することで、異なるオリジン間のAPI通信をスムーズに行うことができます。
  • Preflightリクエストで200 OKが返っても、本体リクエストが失敗する場合は、CORS設定の見直しが必要
  • フロントエンドとバックエンドの整合性を確認し、必要なヘッダーを適切に設定することで、CORSエラーを回避が可能

Discussion