在不是域根的URL上运行Flask应用程序

时间:2014-09-21 17:58:47

标签: python nginx routes flask

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

我希望我的应用的根页面显示在,例如http://example.org/myapp/

我的@ app.route装饰者是例如@app.route('/')代表我的应用的根(http://example.org/myapp)和@app.route('/subpage')代表http://example.org/myapp/subpage等子页面。

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

现在,来自url_for()的我的网址格式为:href="/subpage",它将我发送到域根,http://example.org/subpage而不是我想要的:href="./subpage",其中会带我去http://example.org/myapp/subpage

对于它的价值,我的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服务该应用程序。

根据现状,访问http://example.org/myapp/会将我带到Flask应用程序的根页面,但所有其他网址都会将我带回域级别:http://example.org/subpage

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

2 个答案:

答案 0 :(得分:2)

我知道这是一个老问题,但我遇到了同样的问题,我想要的东西比EricD的答案更好。

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

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

然后在Flask中你有两个选择

选项A

使用实际将HOST标头添加到网址的新url_for。这将采用/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

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

所以在你的烧瓶app中使用

生成url
url_for('index', _external=True)

答案 1 :(得分:1)

尽管 url_for 提到了 APPLICATION_ROOT,但它仅在没有当前请求上下文(即不在 Web 服务器中)时才使用,因此大部分时间根本没有用。

实际机制是通过 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/ 或上游服务器所在的任何位置。