Flask:当我尝试访问索引时出现错误 404

Posted

技术标签:

【中文标题】Flask:当我尝试访问索引时出现错误 404【英文标题】:Flask: get error 404 when I try to access index 【发布时间】:2021-05-21 06:27:33 【问题描述】:

当我使用 flask run 运行 Flask 服务器时,我在索引页面中收到错误 404。

 * Serving Flask app "sf.py"
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [18/Feb/2021 10:25:56] "GET / HTTP/1.1" 404 -

找不到

在服务器上找不到请求的 URL。如果您输入了 URL 请手动检查您的拼写,然后重试。

项目结构
.
├── app
│   ├── models.py
│   ├── routes.py
│   └── __init__.py
├── clients
│   └── client.py
├── migrations
├── tests
│   ├── conftest.py
│   ├── test_models.py
│   ├── test_client.py
│   └── __init__.py
├── publisher.py
├── manage.py
├── run_client.py
├── requirements.txt
└── sf.py
/sf.py
from app import create_app


create_app()
/app/__init__.py
from flask import Flask
from . models import db


POSTGRES = 
    'user': 'sf',
    'pw': 'sf',
    'db': 'sf',
    'host': 'localhost',
    'port': '5432',



def create_app():
    app = Flask(__name__)

    app.config['DEBUG'] = True
    app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % POSTGRES
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    db.init_app(app)

    return app


from app import routes
/app/routes.py
from app import create_app
from app.models import Area, Sensor, Monitoring

from flask import request, jsonify
from flask.views import MethodView


app = create_app()


@app.route('/')
def hello_world():
    return 'Hello, World!'

...

我需要使用create_app(),因为我需要/clients/client.py 使用该应用程序。

/clients/client.py
from paho.mqtt.client import Client
import json

from app import create_app
from app.models import db

from app.models import Monitoring


app = create_app()


class CustomClient(Client):

    def add_reading(self, reading):
        with app.app_context():
            db.session.add(reading)
            db.session.commit()

    def on_connect(self, client, userdata, flags, rc):
        print(
            "Connected:", 
            str(client._host) + ":" + str(client._port)
        )

    def on_subscribe(self, mqttc, obj, mid, granted_qos):
        print(
            "Subscribed:", 
            str(mid), str(granted_qos)
        )

    def on_message(self, client, userdata, message):
        msg = message.payload.decode()
        print(message.topic, msg)
        data = json.loads(msg)
        reading = Monitoring(**data)

        self.add_reading(reading)

    def run(self):
        self.connect("localhost", 1883, 60)
        self.subscribe("Main/#", 0)

        self.loop_forever()

但是这样我得到了 404 错误。而且我不确定我是否正确使用了该应用程序。将应用程序和数据库会话分开来测试模型和客户端而不关心应用程序配置会很好(可能我需要创建一个单独的配置进行测试?)。我错过了什么?

【问题讨论】:

【参考方案1】:

您正在创建Flask() 对象的三个 实例。一个在sf.py 中创建,其他在routes.pyclient.py 中创建。第一个用于为站点提供服务,因此没有您的路由,因为该路由是在routes.py 中创建的实例中注册的。第三个实例,在client.py 是独立的,没有进一步改变,所以这里不是问题;更多内容如下。

不要创建多个副本,至少不要更改一个上的注册并期望这些在另一个上可用。相反,使用blueprints 注册您的视图,然后在您的create_app() 函数中使用Flask() 对象注册蓝图。这样,您可以将路由注册与创建 Flask() 对象分离,并且仍然可以集中注册您的路由。

在您的routes.py 中,使用:

from app.models import Area, Sensor, Monitoring

from flask import Blueprint, request, jsonify
from flask.views import MethodView

bp = Blueprint('main', __name__)

@bp.route('/')
def hello_world():
    return 'Hello, World!'

# ...

然后将该蓝图导入create_app():

def create_app():
    app = Flask(__name__)

    app.config['DEBUG'] = True
    app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://%(user)s:%(pw)s@%(host)s:%(port)s/%(db)s' % POSTGRES
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

    db.init_app(app)

    from . import routes
    app.register_blueprint(routes.bp)

    return app

您希望在create_app() 中进行导入的原因是,在大多数 Flask 应用程序中,您还将使用一个或多个通常在 create_app() 之外创建的 Flask 扩展,以便您的视图可以导入它们。如果您尝试在 routes 模块中导入其中一个对象,并且您的 routes 模块已导入到顶层的 app.py 中,那么您将获得循环导入。

通过此更改(使用蓝图),您可以避免创建一个单独的 Flask() 实例,其中包含用于为您的站点提供服务的主实例不会看到的注册。如果需要(例如,如果您需要使用url_for() 生成 URL),即使您的 client.py 进程现在也可以访问这些路由。

这是我最近为客户构建的生产中 Flask 项目的示例,app.py 模块部分包含以下代码:

from flask import Flask
from flask_babel import Babel
from flask_marshmallow import Marshmallow
from flask_migrate import Migrate
from flask_security import Security, SQLAlchemyUserDatastore
from flask_sqlalchemy import SQLAlchemy


babel = Babel()
db = SQLAlchemy()
ma = Marshmallow()
migrate = Migrate()
security = Security()


_app_init_hooks = []
app_init_hook = _app_init_hooks.append


def create_app():
    app = Flask(__name__)

    for f in _app_init_hooks:
        f(app)

    return app


@app_init_hook
def _configure(app):
    """Load Flask configurations"""

    app.config.from_object(f"__package__.config")

    # optional local overrides
    app.config.from_pyfile("settings.cfg", silent=True)
    app.config.from_envvar("PROJECT_NAME_SETTINGS", silent=True)


@app_init_hook
def _init_extensions(app):
    """Initialise Flask extensions"""

    if app.env != "production":
        # Only load and enable when in debug mode
        from flask_debugtoolbar import DebugToolbarExtension

        DebugToolbarExtension(app)

    # Python-level i18n
    babel.init_app(app)

    # Database management (models, migrations, users)
    from .models import Role, User

    db.init_app(app)
    migrate.init_app(app, db)
    user_datastore = SQLAlchemyUserDatastore(db, User, Role)
    security.init_app(app, user_datastore)

    # Marshmallow integration (must run after db.init_app())
    ma.init_app(app)


@app_init_hook
def _setup_blueprints(app):
    """Import and initialise blueprints"""

    from . import users
    from .sections import BLUEPRINTS

    for blueprint in (*BLUEPRINTS, users.bp):
        app.register_blueprint(blueprint)

    return app

我已将各种组件分解为单独的功能以简化可读性和可维护性,有用于不同站点功能的单独蓝图(这推动了 UI 中的一些自动化)。

模块的顶部是几个 Flask 扩展,各种路由和其他模块需要访问而不必担心循环导入,因此蓝图是在从 @987654346 调用的 _setup_blueprints() 钩子函数内单独导入的@。

您在client.py 中使用create_app() 应该没问题,因为它不会向您希望在其他地方访问的Flask() 实例添加任何新配置,并且大概client.py 在外部使用Flask 网络服务器进程。但就个人而言,我只会将create_app()的结果作为Client 实例的实例属性。你不需要全局,你只需要在调用add_reading() 时轻松访问数据库会话:

class CustomClient(Client):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs):
        # Create a Flask context so we can access the SQLAlchemy session
        self._app = create_app()

    def add_reading(self, reading):
        with self._app.app_context():
            db.session.add(reading)
            db.session.commit()

    # ...

如果add_reading()被频繁调用,可以考虑将app设为CustomClient()的实例属性:

【讨论】:

谢谢!但是对于独立于应用程序运行的 client.py,我需要创建一个新的 Flask 实例吗?因为我认为 client.py 就像一个单独的线程(或作业)。 @EdoardoZucchelli:是的,因为在那个过程中没有 Flask 实例可以以通常的方式访问(例如使用current_app)。所以你是正确的,你需要在那里打电话给create_app()。还有其他方法可以访问 SQLAlchemy 会话和模型,但这种方式更容易。

以上是关于Flask:当我尝试访问索引时出现错误 404的主要内容,如果未能解决你的问题,请参考以下文章

春季注销时出现错误 404

尝试访问本地 LAMP 服务器上的 localhost 时出现 404 Not Found 错误

尝试从 JSP 表单调用 servlet 时出现 404 错误

使用 ajax、php 和 json 服务器发布请求时出现错误 404

“尝试在浏览器窗口中加载我的flask应用程序时出现URL未找到错误”

Spring Security:注销时出现 404