Flask url_for生成http URL而不是https

Bla*_*ise 40 python url-routing werkzeug flask

url_for用户在用户注销时生成重定向网址.

url_for

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

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

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

谢谢.

Mar*_*zer 50

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

url_for('secure_thingy',
        _external=True,
        _scheme='https',
        viewarg1=1, ...)
Run Code Online (Sandbox Code Playgroud)

_scheme设置URL方案,生成一个https://..代替的URL http://.然而,在默认情况下只瓶生成路径(无需主机或方案),所以你需要包括_external=True从去/secure_thingyhttps://example.com/secure_thingy.


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

  • @TheIncorrigible1 它带有下划线前缀,以免与路由参数冲突。我认为私有属性/方法的命名约定不适用于此处。 (3认同)

ald*_*del 28

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

(这个Flask bug似乎证实了这是首选方式.)

基本上,如果您的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)
Run Code Online (Sandbox Code Playgroud)

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

PREFERRED_URL_SCHEME不是这样做的方式.只要请求正在进行中,就会被忽略.


daj*_*obe 25

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

app.config.update(dict(
  PREFERRED_URL_SCHEME = 'https'
))
Run Code Online (Sandbox Code Playgroud)

因为您不必将其添加到每个url_for呼叫.


Tim*_*nin 14

如果您通过代理访问您的网站,那么Flask会正确地检测该方案HTTP.

Browser -----HTTPS----> Reverse proxy -----HTTP----> Flask
Run Code Online (Sandbox Code Playgroud)

最简单的解决方案是配置代理以设置X-Forwarded-Proto标头.Flask将自动检测此标头并相应地管理方案.代理设置部分下的Flask文档中更详细的说明.例如,如果使用Nginx,则必须在location块中添加以下行.

proxy_set_header   X-Forwarded-Proto    $scheme;
Run Code Online (Sandbox Code Playgroud)

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


小智 9

对于最近到这里的人来说,有一个官方的 uwsgi 修复程序: /sf/answers/1645327911/

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)
Run Code Online (Sandbox Code Playgroud)

称为:

app = flask.Flask(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app)
Run Code Online (Sandbox Code Playgroud)

这样,如果您明确设置了环境变量“PREFERRED_URL_SCHEME”,或者 nginx/etc/proxy 设置了 X_FORWARDED_PROTO,它就会做正确的事情。


cvr*_*ert 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)
Run Code Online (Sandbox Code Playgroud)