Flask url_for生成http URL而不是https

时间:2013-02-11 10:56:22

标签: python url-routing flask werkzeug

我正在使用url_for在用户注销时生成重定向网址:

return redirect(url_for('.index', _external=True))

但是,当我将页面更改为 https 连接时,url_for仍然提供 http

我想明确要求url_for在网址开头添加 https

你能指点我怎么改变吗?我看着Flask的文档,没有运气。

7 个答案:

答案 0 :(得分:48)

使用Flask 0.10,可以获得比包裹url_for更好的解决方案。如果您查看https://github.com/mitsuhiko/flask/commit/b5069d07a24a3c3a54fb056aa6f4076a0e7088c7,则会添加_scheme参数。这意味着您可以执行以下操作:

url_for('secure_thingy',
        _external=True,
        _scheme='https',
        viewarg1=1, ...)

_scheme设置网址方案,生成类似https://..而非http://的网址。但是,默认情况下,Flask仅生成路径(没有主机或方案),因此您需要包含从_external=True/secure_thingy的{​​{1}}。


但是,请考虑将您的网站设为仅限HTTPS。您似乎只是尝试为少数“安全”路由部分强制执行HTTPS,但无法确保您的https如果链接到安全页面的页面未加密,则不会更改-URL。这类似于mixed content

答案 1 :(得分:25)

如果您想影响所有服务器生成的网址(redirect_scheme)的网址方案,而不是必须在每次通话时设置environ['wsgi.url_scheme'] = 'https',那么似乎“正确的“答案是使用WSGI中间件,如本摘录中所述:get output from a paramiko ssh exec_command continuously

http://flask.pocoo.org/snippets/35/似乎证实这是首选方式。)

基本上,如果您的WSGI环境有url_for,则https:会生成http://个网址。

我从url_for获取class ReverseProxied(object): def __init__(self, app): self.app = app def __call__(self, environ, start_response): scheme = environ.get('HTTP_X_FORWARDED_PROTO') if scheme: environ['wsgi.url_scheme'] = scheme return self.app(environ, start_response) app = Flask(__name__) app.wsgi_app = ReverseProxied(app.wsgi_app) 个网址,因为我的服务器部署在Elastic Beanstalk负载均衡器后面,后者通过常规HTTP与服务器通信。我的解决方案(特定于Elastic Beanstalk)就像这样(从上面链接的片段中简化):

HTTP_X_FORWARDED_PROTO

特定于Elastic Beanstalk的部分是environ['wsgi.url_scheme'] = 'https'。其他环境可以通过其他方式确定外部URL是否包含https。如果您只想使用HTTPS,则可以无条件地设置PREFERRED_URL_SCHEME

SELECT categorias.categoria_nombre ,categorias.seccion ,tipo_item.nombre ,tipo_item.detalle ,items.codigo_barra FROM categorias INNER JOIN tipo_item ON ( categorias.id = tipo_item.categoria AND categorias.secion = '$dato' AND categorias.categoria_nombre = '$dato_extra' ) INNER JOIN items ON ( tipo_item.id = items.tipo_item AND $ESTADO ) LIMIT 100 OFFSET $offset 不是这样做的方法。这是This Flask bug

答案 2 :(得分:23)

我使用url_for arg尝试了接受的答案,但我发现使用PREFERRED_URL_SCHEME配置变量并将其设置为https更容易:

app.config.update(dict(
  PREFERRED_URL_SCHEME = 'https'
))

因为您不必将其添加到每个url_for来电。

答案 3 :(得分:11)

如果您通过Nginx等反向代理访问您的网站,那么Flask会正确地判断该方案为HTTP

Browser -----HTTPS----> Reverse proxy -----HTTP----> Flask

最简单的解决方案是配置反向代理以设置X-Forwarded-Proto标头。 Flask将自动检测此标头并相应地管理方案。有一个more detailed explanation in the Flask documentation under the Proxy Setups section。例如,如果您使用Nginx,则必须在location块中添加以下行。

proxy_set_header   X-Forwarded-Proto    $scheme;

正如其他提到的,如果您无法更改代理的配置,您可以使用werkzeug ProxyFix或构建您自己的修补程序,如文档中所述: http://flask.pocoo.org/docs/0.12/deploying/wsgi-standalone/#proxy-setups

答案 4 :(得分:8)

在每次_scheme来电时设置url_for()非常繁琐,PREFERRED_URL_SCHEME似乎无法正常工作。但是,如果请求的假设方案处于WSGI级别,则可能会成功说服Flask始终构建HTTPS URL:

def _force_https(app):
    def wrapper(environ, start_response):
        environ['wsgi.url_scheme'] = 'https'
        return app(environ, start_response)
    return wrapper

app = Flask(...)

app = _force_https(app)

答案 5 :(得分:1)

对于最近在这里结束的任何人,有一个官方的uwsgi修复程序用于此操作: https://stackoverflow.com/a/23504684/13777925

FWIW对于我来说仍然不起作用,因为标头设置不正确,所以我对ReversedProxied中间件进行了扩充,使其更倾向于使用https:

class ReverseProxied(object):
"""
Because we are reverse proxied from an aws load balancer
use environ/config to signal https
since flask ignores preferred_url_scheme in url_for calls
"""

    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        # if one of x_forwarded or preferred_url is https, prefer it.
        forwarded_scheme = environ.get("HTTP_X_FORWARDED_PROTO", None)
        preferred_scheme = app.config.get("PREFERRED_URL_SCHEME", None)
        if "https" in [forwarded_scheme, preferred_scheme]:
            environ["wsgi.url_scheme"] = "https"
        return self.app(environ, start_response)

称为:

app = flask.Flask(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app)

通过这种方式,如果您明确设置了环境变量“ PREFERRED_URL_SCHEME”,或者如果nginx / etc / proxy设置了X_FORWARDED_PROTO,它将做正确的事。

答案 6 :(得分:0)

我个人无法通过此处的任何答案解决此问题,但发现只需将 --cert=adhoc 添加到flask run 命令的末尾,使flask 应用程序使用https 运行即可解决问题。< /p>

flask run --host=0.0.0.0 --cert=adhoc

相关问题