65

url_for用于在用户注销时生成重定向 URL:

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

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

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

你能指点我如何改变它吗?我查看了 Flask 文档,没有运气。

4

7 回答 7

69

使用 Flask 0.10,将会有比 wrapping 更好的解决方案url_for。如果您查看https://github.com/mitsuhiko/flask/commit/b5069d07a24a3c3a54fb056aa6f4076a0e7088c7_scheme则添加了一个参数。这意味着您可以执行以下操作:

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

_scheme设置 URL 方案,生成一个 URL,https://..而不是http://. 但是,默认情况下 Flask 只生成路径(没有主机或方案),因此您需要包含_external=Trueto go from /secure_thingyto https://example.com/secure_thingy


但是,请考虑将您的网站设置为仅 HTTPS。似乎您正在尝试仅对少数“安全”路由部分强制实施 HTTPS,但如果链接到安全页面的页面未加密,则无法确保不会更改您的 https-URL。这类似于混合内容

于 2013-02-27T12:17:54.487 回答
54

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

这个 Flask 错误似乎证实了这是首选方式。)

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

我从中获取http://URL 是url_for因为我的服务器部署在 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不是这样做的方法。只要请求正在进行,它就会被忽略。

于 2016-06-15T17:53:12.177 回答
32

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

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

因为您不必将其添加到每个url_for呼叫中​​。

于 2014-10-29T17:23:28.043 回答
29

如果您通过 Nginx 等反向代理访问您的网站,那么 Flask 会正确检测到HTTP.

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

最简单的解决方案是配置您的反向代理来设置X-Forwarded-Proto标头。Flask 会自动检测这个 header 并相应地管理方案。Flask 文档中的 Proxy Setups 部分有更详细的解释。例如,如果您使用 Nginx,则必须在location块中添加以下行。

proxy_set_header   X-Forwarded-Proto    $scheme;

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

于 2017-08-15T12:45:27.950 回答
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)
于 2015-01-31T02:34:43.207 回答
7

对于最近在这里结束的任何人,都有一个官方的 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,它会做正确的事情。

于 2020-07-28T23:08:42.517 回答
0

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

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

于 2021-06-29T15:13:20.933 回答