Flask url_for生成http URL而不是https

问题描述 投票:34回答:5

当用户注销时,我使用url_for生成重定向URL:

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

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

我想明确要求url_for在URL的开头添加https。

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

python url-routing flask werkzeug
5个回答
49
投票

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

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

_scheme设置URL方案,生成像https://..而不是http://的URL。但是,默认情况下,Flask只生成路径(没有主机或方案),因此您需要包含_external=True以从/secure_thingy转到https://example.com/secure_thingy


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


27
投票

如果你想影响所有服务器生成的URL(url_forredirect)的URL方案,而不是必须在每次调用时设置_scheme,似乎“正确”的答案是使用WSGI中间件,如在此片段中:http://flask.pocoo.org/snippets/35/

This Flask bug似乎证实这是首选方式。)

基本上,如果您的WSGI环境有environ['wsgi.url_scheme'] = 'https',那么url_for将生成https: URL。

我从http://获取url_for URL,因为我的服务器部署在Elastic Beanstalk负载均衡器后面,后者通过常规HTTP与服务器通信。我的解决方案(特定于Elastic Beanstalk)就像这样(从上面链接的代码段中简化):

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_X_FORWARDED_PROTO。其他环境可以通过其他方式确定外部URL是否包含https。如果您只想使用HTTPS,则可以无条件地设置environ['wsgi.url_scheme'] = 'https'

PREFERRED_URL_SCHEME不是这样做的方式。这是ignored whenever a request is in progress


23
投票

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

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

因为你不必将它添加到每个url_for调用。


13
投票

如果您通过像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


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)
© www.soinside.com 2019 - 2024. All rights reserved.