Flask API调用出现404错误,寻求技术排查解决方案
问题描述
在Docker双容器(Flask + PostgreSQL)环境中运行Flask API时,所有GET、POST请求均返回404错误码。已通过PGAdmin手动创建数据库表(Flask Migrations功能失效),多次确认服务器URL配置无误,但仍无法定位问题,附上相关代码片段求助。
init.py 文件
import os from flask_migrate import Migrate from flask import Flask from flask_sqlalchemy import SQLAlchemy def create_app(test_config=None): app = Flask(__name__, instance_relative_config=True) app.config.from_mapping( SECRET_KEY='dev', SQLALCHEMY_DATABASE_URI = 'postgresql://postgres@localhost:5432/amazonclone', SQLALCHEMY_TRACK_MODIFICATIONS=False, SQLALCHEMY_ECHO=True ) if test_config is None: # 加载实例配置(如果存在) app.config.from_pyfile('config.py', silent=True) else: # 加载测试配置 app.config.from_mapping(test_config) # 确保实例文件夹存在 try: os.makedirs(app.instance_path) except OSError: pass db = SQLAlchemy(app) migrate = Migrate(app, db) return app
wsgi.py 文件
from src import create_app app = create_app() if __name__ == "__main__": app.run(host='0.0.0.0', port=5000)
API路由文件(部分内容)
from flash import Flask, jsonify, request, abort # 注意:此处有拼写错误 from bookModel import Book, BookSchema from clothingModel import Clothing, ClothingSchema from movieModel import Movie, MovieSchema from home_garden import HomeAndGarden, HomeAndGardenSchema from electronic import Electronic, ElectronicSchema from flask_sqlalchemy import SQLAlchemy from flask_marshmallow import Marshmallow app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres@localhost:5432/amazonclone' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) ma = Marshmallow(app) # Book路由 @app.route('/books', methods=['POST']) def add_book(): # 检查请求体是否包含所有必填字段 if not all(key in request.json for key in ['genre', 'author', 'style', 'name']): abort(400, 'Missing required keys in Json payload') # 从请求体获取数据 genre = request.json['genre'] author = request.json['author'] style = request.json['style'] name = request.json['name'] # 创建新Book对象并添加到数据库 my_books = Book(genre, author, style, name) db.session.add(my_books) db.session.commit() # 序列化并返回新对象 return jsonify(Book.dump(my_books)), 201
问题分析与修复方案
核心问题:路由未注册到运行的Flask实例
当前代码中,路由文件新建了一个独立的Flask实例,而wsgi.py中运行的是create_app()创建的另一个实例——两个实例完全独立,导致定义的路由根本没有被加载到正在运行的API服务中,这是所有请求返回404的直接原因。
其他关键问题
- Docker环境下数据库地址错误:容器内的
localhost指向Flask容器本身,而非PostgreSQL容器,需要用PostgreSQL容器的名称作为主机名(例如postgres,需与docker-compose.yml中的服务名一致)。 - Migrations失效:
create_app()中初始化了Migrate,但未导入任何模型类,导致Migrate无法识别数据库模型,无法生成迁移文件。 - 导入拼写错误:路由文件中
from flash import Flask是错误拼写,应为from flask import Flask,会直接导致路由文件无法正常加载。
具体修复步骤
1. 统一Flask实例,用蓝图管理路由
这是Flask项目组织路由的标准方式,避免多实例冲突:
- 修改路由文件,删除独立的
Flask、db、ma初始化代码,改用蓝图(Blueprint):
from flask import Blueprint, jsonify, request, abort # 修正导入拼写 from bookModel import Book, BookSchema # 其他模型导入保持不变 from src import db # 从create_app的实例中导入db # 创建蓝图 bp = Blueprint('products', __name__) # Book路由 @bp.route('/books', methods=['POST']) def add_book(): if not all(key in request.json for key in ['genre', 'author', 'style', 'name']): abort(400, 'Json payload缺少必填字段') genre = request.json['genre'] author = request.json['author'] style = request.json['style'] name = request.json['name'] my_books = Book(genre, author, style, name) db.session.add(my_books) db.session.commit() return jsonify(BookSchema().dump(my_books)), 201
- 在
__init__.py的create_app函数末尾注册蓝图:
def create_app(test_config=None): # ... 原有代码保持不变 ... db = SQLAlchemy(app) # 导入所有模型类(修复Migrations失效) from .bookModel import Book from .clothingModel import Clothing from .movieModel import Movie from .home_garden import HomeAndGarden from .electronic import Electronic migrate = Migrate(app, db) # 注册路由蓝图 from .routes import bp as products_bp app.register_blueprint(products_bp) return app
2. 修正Docker环境下的数据库连接地址
将__init__.py中的SQLALCHEMY_DATABASE_URI修改为:
SQLALCHEMY_DATABASE_URI = 'postgresql://postgres@postgres:5432/amazonclone'
注:postgres为PostgreSQL容器的服务名称,需与你的docker-compose.yml中定义的服务名一致。
3. 验证路由加载
启动服务后,可以通过以下代码在wsgi.py中打印所有注册的路由,确认路由是否被正确加载:
from src import create_app app = create_app() # 打印所有路由 print("Registered Routes:") for rule in app.url_map.iter_rules(): print(f"{rule.methods} {rule.rule}") if __name__ == "__main__": app.run(host='0.0.0.0', port=5000)
内容的提问来源于stack exchange,提问作者Babit56
相关产品推荐
相关产品推荐

