フロントエンドにReact、バックエンドにFlaskを使用してWebアプリを作ろうとしたときハマったことを、備忘録としてまとめておきます。間違っている部分、追加部分ございましたらどんどん教えてください。
ハマった内容
- post先の関数名が間違っている。
- テーブルへのデータ書き込みは事前に行う
-
net::ERR_EMPTY_RESPONSE
が起きる。 - CORS エラーが起きる。
Postを送る前に確認すべきこと
1. 関数名間違い
Postの送り先の関数名が合っているか確認する(大文字、小文字も合わせる)。
2. テーブルへのデータ書き込み確認
バックエンド側で事前にデバッグを行っておくと、フロントエンド側との連携がスムーズになります。テーブルにデータを書き込む確認は、以下のように簡単に行うことができます。
import os
from flask import Flask, flash, jsonify, render_template, request
from flask_cors import CORS
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
from src.utils import get_db_connect_url
URI = get_db_connect_url("postgres")
def create_app(uri: str) -> Flask:
"""
Flaskアプリを作成する
"""
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = uri
app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY")
return app
app = create_app(URI)
db = SQLAlchemy(app)
ma = Marshmallow(app)
CORS(app, origins=["http://127.0.0.1:5173"])
class Base(db.Model):
__abstract__ = True
class tableUser(Base):
"""
ユーザーのテーブル
"""
__tablename__ = "User"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(120), nullable=False)
if __name__ == "__main__":
# 値の書き込み確認
username = "hogehoge"
email = "hogehoge@gmial.com"
password = "hogehoge"
new_user = tableUser(username=username, email=email, password=password)
relationを使っている場合、この段階でエラーが発生しデータの書き込みができません。フロントエンド側と合わせてデバッグを行おうとすると、CORS エラーなど他のエラーとしてブラウザ側に表示されるため、発見が難しいです(この辺り、まとめてデバッグする方法もあるかもしれません…)。よって、事前のデバッグがおすすめです。
Docker を使用した開発で確認すべきこと
1. net::ERR_EMPTY_RESPONSE
が起き
1.1. 原因
Dockerコンテナは -p コマンドもしくはdocker-compose.ymlの設定を使用してhostマシンとコンテナのポートを繋げておかないと(マッピングという)、コンテナの外部から内部にアクセスができない仕組みになっています。
例えば、docker run を使用してコンテナを構築する際には以下のようなコマンドを使用することができます。
docker run -d --name http_server -p 3000:3000 python:3.11 python -m http.server -b localhost
docker-compose.ymlを使用する場合は、以下のように記述します。
version: "3"
services:
react-app:
build:
args:
- BASE_IMAGE=node:latest
context: .
dockerfile: ./app/react_Dockerfile
tty: true
volumes:
- ../app:/home/
ports:
- 3000:3000
この設定により、host側のポート3000をコンテナ側のポート3000にマッピングしました。しかし、この状態でlocalhost:3000にアクセスしてもコンテナ内のサーバにまでアクセスすることはできません。これは、ホスト側のlocalhostとコンテナ側のlocalhostが異なるためです。下記の記事で詳細に解説されています。
1.2. 解決方法
記事で述べられている通り、コンテナ側のサーバのIPアドレスを0.0.0.0にすることで問題を解決できました。
Flask の場合、以下のようにすることでサーバのIPアドレスとポートを指定することができます。
app.run(debug=True, host="0.0.0.0", port=5000)
2. CORS エラーが起きる
2.1. 原因
上記のエラーと同様、フロントエンド側からバックエンド側にアクセスする際に発生するエラーです。メッセージは以下の通りです。
Access to XMLHttpRequest at 'http://localhost:5000/register' from origin 'http://127.0.0.1:5173' has been blocked by CORS policy
CORSとは、オリジン間リソース共有 (Cross-Origin Resource Sharing) の略で、異なるオリジンからのアクセスを制限する仕組みのこと。
オリジンとは、URL中のスキーム (プロトコル)、 ホスト (ドメイン)、 ポート番号の組み合わせのこと
http://example.com
の場合
- スキーム:
http
- ホスト:
example.com
- ポート:
80
(省略可能)- 以下のようにスキーム (
http
) とホスト名 (example.com
) が同じ場合は同一オリジン
http://example.com/app1/index.html
http://example.com/app2/index.html
下記の記事を参考にしました。
2.2. 解決方法
バックエンド側にflask_cors
を追加することで解決しました。
以下、GitHub Cpilotの回答になります。
この問題を解決するには、FlaskアプリケーションでCORSを許可する必要があります。Flask-CORSという拡張を使用すると、簡単にCORSを設定できます。
まず、Flask-CORSをインストールします:
pip install -U flask-cors
次に、FlaskアプリケーションでCORSを有効にします:
from flask_cors import CORS app = Flask(__name__) CORS(app)
これで、すべてのオリジンからのリクエストが許可されます。特定のオリジンのみを許可するには、CORS関数にオリジンを指定します:
CORS(app, origins=["http://127.0.0.1:5173"])
これで、CORSエラーが解消されるはずです。
CORS(app, origins=["****"])
の * * * * 部分はフロントエンド側のデバッグの際にブラウザに表示されているURLとポートを指定してください。
まとめ
以上が今回ハマったエラーになります。Webアプリは初心者のため1回ハマると1つ解決するだけでもとても時間がかかりました。この情報が何かお役に立てればと思います。