【问题标题】:Running a Flask application at a URL that is not the domain root在不是域根的 URL 上运行 Flask 应用程序
【发布时间】:2014-11-15 17:15:50
【问题描述】:

我正在将 Flask 应用程序从 apache2 和 mod_wsgi 环境移动到 Nginx,并且在让 url 正常工作时遇到问题。

我希望我的应用的根页面出现在例如@987654321@

我的 @app.route 装饰器是例如@app.route('/') 用于我的应用程序的根目录 (@987654322@),@app.route('/subpage') 用于@987654323@ 等子页面。

在 apache 下,这一切都“正常工作”,我对 url_for() 的调用产生了完成工作的 URL。

现在我来自 url_for() 的 URL 的格式为:href="/subpage",这会将我发送到域根目录 @987654324@,而不是我想要的:href="./subpage",这会将我带到 @987654325@

对于它的价值,我的 Nginx 配置中的相关部分是:

    location /myapp/ {
        proxy_redirect     off;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
        proxy_pass         http://127.0.0.1:8001/;
    }

我正在使用 gunicorn 为应用程序提供服务。

在目前的情况下,访问@987654326@ 会将我带到我的 Flask 应用程序的根页面,但所有其他 URL 会将我带回到域级别:@987654327@

我尝试将 APPLICATION_ROOT 设置为“/myapp”,但似乎没有效果。我在做什么(可怕的)错误?

【问题讨论】:

    标签: python nginx flask gunicorn wsgi


    【解决方案1】:

    在您的 nginx 配置中,您应该使用包含您的应用所在的子路径的 HOST 标头代理传递:

    location /myapp {
        ...
        proxy_set_header   Host $host/myapp;
        ...
    }
    

    那么在 Flask 中你有两个选择

    选项 A

    使用新的url_for,它实际上将 HOST 标头添加到 url。这将采用类似/mypage 的路径并将其转换为/myapp/mypage

    from urllib.parse import urlparse
    from flask import request, url_for as _url_for
    
    def url_with_host(path):
        return '/'.join((urlparse(request.host_url).path.rstrip('/'), path.lstrip('/')))
    
    
    def url_for(*args, **kwargs):
        if kwargs.get('_external') is True:
            return _url_for(*args, **kwargs)
        else:
            return url_with_host(_url_for(*args, **kwargs))
    

    您甚至可以使用以下方法更新 Jinja url_for

    app.jinja_env.globals['url_for'] = url_for
    

    选项 B

    url_for 中使用_external 标志。这将呈现具有完整路径的链接,例如:http://www.example.com/myapp/mypage

    所以在你的烧瓶应用程序中生成 url 的使用

    url_for('index', _external=True)
    

    【讨论】:

    • 这些都是非常讨厌的解决方法,忽略了实际的标准方法
    • 例如,包含路径的Host 标头无效。
    【解决方案2】:

    尽管url_for 提到了APPLICATION_ROOT,它只在没有当前请求上下文的情况下使用(即不在网络服务器中),所以大部分时间都没有用。

    实际的机制是通过 wsgi 变量SCRIPT_NAME。使用gunicorn,您可以通过几种方式在命令行中传递它:

    gunicorn --env SCRIPT_NAME=/myapp app:app
    
    SCRIPT_NAME=/myapp gunicorn app:app
    

    在某些 wsgi 系统中(例如mod_wsgi),它也可以作为请求标头传递。

    为此,您需要在反向代理处剥离路径。 nginx 配置应该是:

    location /myapp {
        proxy_pass http://localhost:8000/myapp/;
        proxy_set_header Host $host;
        proxy_redirect off;
    }
    

    http://unix:/run/gunicorn.sock/myapp/ 或上游服务器所在的任何位置。

    【讨论】:

      猜你喜欢
      • 2021-08-31
      • 2013-01-08
      • 2015-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-09
      • 1970-01-01
      相关资源
      最近更新 更多