我正在使用url_for
生成一个重定向URL,当用户注销时使用:
return redirect(url_for('.index', _external=True))
然而,当我将页面更改为https连接时,url_for
仍然给我http。我想明确要求
url_for
在URL开头添加https。你能指导我如何更改吗?我查看了Flask文档,但没有找到。
我正在使用url_for
生成一个重定向URL,当用户注销时使用:
return redirect(url_for('.index', _external=True))
然而,当我将页面更改为https连接时,url_for
仍然给我http。url_for
在URL开头添加https。使用 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
。
_scheme
设为私有参数。至少它能工作。 - Maximilian Burszleyurl_for
和redirect
),而不是每次调用都设置_scheme
,则似乎“正确”的答案是使用WSGI中间件,例如此代码片段:http://flask.pocoo.org/snippets/35/(此Flask错误似乎确认这是首选方法。)基本上,如果您的WSGI环境具有environ ['wsgi.url_scheme'] ='https'
,则url_for
将生成https:
URL。因为我的服务器部署在Elastic Beanstalk负载均衡器后面,该负载均衡器使用常规HTTP与服务器通信,所以我从url_for
获取了http:
URL。我的解决方案(特定于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
不是实现此目的的方法。它在请求正在进行时被忽略。
app.wsgi_app = ProxyFix(app.wsgi_app)
的行,您仍然应该能够添加aldel的解决方案而不会发生冲突。至少对我来说是这样的。 - N. QuestHTTP_X_FORWARDED_PROTO
没有发送到服务器,因此我不得不设置environ['wsgi.url_scheme'] = 'https'
,无论服务器发送了什么(我不想在任何情况下使用http)。 - Tim LudwinskiProxyFix
应该已经处理了这个问题,无需定义自己的中间件。https://werkzeug.palletsprojects.com/en/2.2.x/middleware/proxy_fix/ - undefined如果您通过类似 Nginx 的反向代理访问您的网站,则 Flask 会正确地检测到方案为 HTTP
。
Browser -----HTTPS----> Reverse proxy -----HTTP----> Flask
最简单的解决方案是配置反向代理以设置X-Forwarded-Proto
头。 Flask将自动检测此标头并相应地管理协议。在Flask文档的代理设置部分中,有一份更详细的说明。例如,如果您使用Nginx,则需要在location
块中添加以下行。
proxy_set_header X-Forwarded-Proto $scheme;
正如其他人提到的,如果您无法更改代理的配置,您可以使用werkzeug ProxyFix或根据文档中描述的方式构建自己的修复程序: http://flask.pocoo.org/docs/0.12/deploying/wsgi-standalone/#proxy-setups
url_for
参数,但我发现使用PREFERRED_URL_SCHEME
配置变量并将其设置为https更容易:app.config.update(dict(
PREFERRED_URL_SCHEME = 'https'
))
由于您不需要将其添加到每个url_for
调用中。
在每次调用 url_for()
时设置 _scheme
非常繁琐,而且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)
最近来到这里的任何人,现在有一个官方的uwsgi修复程序: https://dev59.com/N2Ag5IYBdhLWcg3wpMWz#23504684
顺便说一下,对于我来说这仍然不起作用,因为标头没有被正确设置,所以我增加了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等代理服务器设置了X_FORWARDED_PROTO,那么它就会做正确的事情。
preferred_scheme = app...
中的 app
不是 self.app
(WSGI 应用程序),而是 Flask 应用程序。 - moi--cert=adhoc
即可使flask应用程序以https方式运行,从而解决了这个问题。
flask run --host=0.0.0.0 --cert=adhoc
ingress:
web:
enabled: true
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
https
通常由 WSGI 处理程序处理。 - Jakob Bowyerpython index.py
即可。这是Flask的wsgi处理程序。还请查看 @leon 的回答。 - Blaise