在 uWSGI/Gunicorn 上使用 Flask 的所有路由都是 404

404 for all routes with Flask on uWSGI/Gunicorn

我找到并分叉了以下 Flask/SQLAlchemy/Marshmallow 示例项目:

https://github.com/summersab/RestaurantAPI

它就像一个魅力,我用它来构建一个自定义 API。 运行完美搭配:

python run.py

然后,我尝试 运行 它在合适的网络服务器上:

uwsgi --http localhost:5000 --wsgi-file run.py --callable app

但是,除了 //api/api/v1.0 之外的所有路线我都得到 404。我在 Gunicorn 上试过,结果相同,这让我相信问题出在代码上,而不是网络服务器配置上。

以下所有帖子都有同样的问题,但据我所知,none 个帖子有适合我的解决方案(我可能遗漏了一些东西):

有人可以查看我的代码库中的代码并帮助我找出问题所在吗?

编辑:

根据@v25 的回复,我将 run.py 更改为以下内容:

from flask import Flask, redirect, render_template
from app import api_bp
from model import db, redis_cache
from config import DevelopmentConfig, TestingConfig, BaseConfig, PresentConfig

app = Flask(__name__)

t = 0
def create_app(config_filename):
    app.config.from_object(config_filename)
    global t
    if t == 0:
        app.register_blueprint(api_bp, url_prefix='/api/v1.0')
        t = 1
    if config_filename != TestingConfig:
        db.init_app(app)
        redis_cache.init_app(app)
    return app

@app.route('/')
@app.route('/api/')
@app.route('/api/v1.0/')
def availableApps():

    return render_template('availableApp.html')

PresentConfig = BaseConfig
app = create_app(PresentConfig)

if __name__ == "__main__":
    app.run(use_debugger=False, use_reloader=False, passthrough_errors=True)

然后我 运行 使用 uwsgi,它按预期工作:

uwsgi --http localhost:5000 --wsgi-file run.py --callable app

感谢您的帮助!

这可以通过创建一个包含以下内容的新文件 wsgi.py 来快速解决:

import run
PresentConfig = run.BaseConfig
app = run.create_app(PresentConfig)

然后执行:

uwsgi --http localhost:5000 --wsgi-file wsgi.py --callable app

或...

gunicorn --bind 'localhost:5000' wsgi:app

为什么这样做...

如果您有 look inside the run.py file,请注意直接使用 python 启动它时发生的情况:

if __name__ == "__main__":
    PresentConfig = BaseConfig
    app = create_app(PresentConfig)
    app.run(use_debugger=False, use_reloader=False, passthrough_errors=True)

您可以看到正在创建 app,基于传递给配置的 create_app 函数的 return 值。另请注意,create_app 函数将 "other URLs" 注册为 api_bp 蓝图的一部分。

然而,当使用 uwsgi/gunicorn 执行应用程序时,此 if 子句中的代码永远不会执行;相反,导入的 app 对象是一个没有注册其他 URL 的对象。

通过创建上面的 wsgi.py 文件,您正在以一种随后可以由 wsgi/gunicorn 可执行文件改进的方式执行所有这些操作。


考虑到这一点,解决此问题的另一种方法是更改​​ run.py 的最后四行,使其看起来更像:

PresentConfig = BaseConfig
app = create_app(PresentConfig)

if __name__ == "__main__":    
    app.run(use_debugger=False, use_reloader=False, passthrough_errors=True)

然后您可以使用原始 wsgi 命令执行此操作。

值得注意的是,这可能会破坏其他执行 from run import app 并期望 app 不是 create_app 的 return 值的代码(在这种情况下不太可能)。

如果您需要任何说明,请告诉我。