0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【備忘】フロントエンドとバックエンドをAPIで疎通させようとしたらリクエストがNullになり詰まった

Posted at

最初に実装していたソースコード

フロントエンド

request_data = {
    key = value,
    key2 = value2
}

const URL = "https://api_endpint/xx/yyy",

const response = await fetch(URL, {
    method: "POST",
    mode: "cors",
    headers: {
        "Content-Type": "application/json",
    },
    body: JSON.stringify(requestData),
});

バックエンド

"""
中略
"""

@aaa_blueprint.route('/xx/yyy', methods=['OPTION', 'POST'])
def example_route():
    try:
        request_data = request.get_json(silent=True)
        logger.info(f"取得したリクエストデータ: {request_data}")

        return response_example
    except Exception as e:
        logger.exception(f"エラーが発生しました: {e}")
        raise e

Error

debug.log
ERROR - 取得したリクエストデータ: None

原因

バックエンドでリクエストを受け取る時に「OPTION」を許可しておきながら、OPTIONを適切に処理する処理を実装していなかったから

解決策

クロスアクセスオリジンを許可しない場合。

バックエンドで受け入れるメソッドからOPTIONを削除しよう

"""
中略
"""

@aaa_blueprint.route('/xx/yyy', methods=['POST']) #OPTIONを削除
def example_route():
    try:
        request_data = request.get_json(silent=True)
        logger.info(f"取得したリクエストデータ: {request_data}")
        
        """
        ここにビジネスロジック処理
        """

        return response_example
    except Exception as e:
        logger.exception(f"エラーが発生しました: {e}")
        raise e

クロスオリジンを許可する場合

バックエンドでまずOPTIONを受け入れるメソッドを用意して、分離しよう

"""
中略
"""

@aaa_blueprint.route('/xx/yyy', methods=['POST']) #OPTIONを削除
def example_route():
    try:
        request_data = request.get_json(silent=True)
        logger.info(f"取得したリクエストデータ: {request_data}")

        """
        ここにビジネスロジック処理
        """

        return response_example
    except Exception as e:
        logger.exception(f"エラーが発生しました: {e}")
        raise e

"""
OPTIONを受け入れる部分のルートを設定
"""
@aaa_blueprint.route('/xx/yyy', methods=['OPTIONS'])
def options_handler():
    response = jsonify()
    response.headers.add("Access-Control-Allow-Origin", "*")
    response.headers.add("Access-Control-Allow-Methods", "POST, OPTIONS")
    response.headers.add("Access-Control-Allow-Headers", "Content-Type")
    return response

詳細な仕組み

注意:調べてみてのまとめになります。初心者のため理解に誤りがあればコメントで指摘をお願いします!

まず、OPTIONメソッドについて

OPTIONSメソッドは、主にCORS(Cross-Origin Resource Sharing)関連で使用されます。CORSは、ブラウザが異なるオリジンからリソースを読み込む際に、リクエストが安全であるかどうかを確認するための仕組みです。

OPTIONSメソッド: CORSプリフライトリクエストに使われることが多いです。ブラウザが異なるオリジン(例えば、フロントエンドがlocalhost:5173、バックエンドがlocalhost:5001)にリクエストを送信する場合、最初にOPTIONSリクエストを送り、サーバーがそのリクエストを許可するかを確認します。サーバーが適切なCORSヘッダーを返すと、実際のリクエスト(例えばPOST)が送信されます。

したがって、OPTIONSメソッドを受け入れることで、CORSプリフライトリクエストに対応し、クロスオリジンのリクエストが正常に処理できるようになります。

次にPOSTメソッドについて
リクエストでPOSTメソッドを使用する場合、ブラウザがCORSのプリフライトリクエスト(OPTIONSメソッド)を送信することがありますが、サーバーがOPTIONSメソッドに適切に応答できるようにしておく必要があります。

もしOPTIONSメソッドをバックエンドで処理しなかった場合、ブラウザがOPTIONSリクエストを送信し、その後にPOSTリクエストが送信される前にエラーが発生します。逆に、POSTメソッドだけを処理する場合、CORSが問題になると、プリフライトリクエスト(OPTIONS)に適切に応答できないため、POSTリクエストがブロックされることがあります。

つまり

CORSを有効化したい場合、フロントから2回リクエストが送られていたようです。
1回目:CORSが許可されているかな?の確認リクエスト
2回目:本リクエスト(実データが含まれている)

上記を元に最初の実装を振り返ってみると?

OPTIONとPOSTを同じエンドポイントでうけたことにより、OPTIONを受け取った状態でビジネスロジック処理に繋げていてしまったので、「は?bodyねえじゃん?エラーです」となっていたわけです。

ということで、ビジネスロジック用のエンドポイントとCORSプリフライトリクエストを受けるエンドポイントを分離しておくことで、ビジネスロジッの処理に入ることができるようになったわけですね。

APIは便利ですが、裏側でどうなっているのかを少しだけ知ることができました。

(公式ドキュメントからは分からなかったので、ログとソースを見比べて、少し修正したらchatGPTに投げて、もう一回修正して・・・の繰り返しで、なんか上手くいったからchatGPTに何をしたかとその理由を教えて欲しいと聞いたら教えてくれただけなのですが・・・)

あくまでも自分の備忘用の記載になるので、お手柔らかに・・・

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?