[英]Flask url_for generating http URL instead of https
I am using url_for
to generate a redirect URL when a user has logged out:当用户注销时,我使用
url_for
生成重定向 URL:
return redirect(url_for('.index', _external=True))
However, when I changed the page to a https connection, the url_for
still gives me http .但是,当我将页面更改为https连接时,
url_for
仍然给我http 。
I would like to explicitly ask url_for
to add https at the beginning of a URL.我想明确要求
url_for
在 URL 的开头添加https 。
Can you point me how to change it?你能指点我怎么改吗? I looked at Flask docs, without luck.
我查看了 Flask 文档,但运气不佳。
With Flask 0.10, there will be a much better solution available than wrapping url_for
.使用 Flask 0.10,将有一个比包装
url_for
更好的解决方案。 If you look at https://github.com/mitsuhiko/flask/commit/b5069d07a24a3c3a54fb056aa6f4076a0e7088c7 , a _scheme
parameter has been added.如果您查看https://github.com/mitsuhiko/flask/commit/b5069d07a24a3c3a54fb056aa6f4076a0e7088c7 ,
_scheme
添加一个_scheme
参数。 Which means you can do the following:这意味着您可以执行以下操作:
url_for('secure_thingy',
_external=True,
_scheme='https',
viewarg1=1, ...)
_scheme
sets the URL scheme, generating a URL like https://..
instead of http://
. _scheme
设置 URL 方案,生成一个 URL,如https://..
而不是http://
。 However, by default Flask only generates paths (without host or scheme), so you will need to include the _external=True
to go from /secure_thingy
to https://example.com/secure_thingy
.但是,默认情况下 Flask 仅生成路径(没有主机或方案),因此您需要包含
/secure_thingy
_external=True
以从/secure_thingy
转到https://example.com/secure_thingy
。
However, consider making your website HTTPS-only instead.但是,请考虑让您的网站仅使用 HTTPS。 It seems that you're trying to partially enforce HTTPS for only a few "secure" routes, but you can't ensure that your https-URL is not changed if the page linking to the secure page is not encrypted.
似乎您试图仅对少数“安全”路由部分强制执行 HTTPS,但如果链接到安全页面的页面未加密,则无法确保您的 https-URL 不会更改。 This is similar to mixed content .
这类似于混合内容。
If you want to affect the URL scheme for all server-generated URLs ( url_for
and redirect
), rather than having to set _scheme
on every call, it seems that the "correct" answer is to use WSGI middleware, as in this snippet: http://flask.pocoo.org/snippets/35/如果您想影响所有服务器生成的 URL(
url_for
和redirect
)的 URL 方案,而不必在每次调用时设置_scheme
,似乎“正确”的答案是使用 WSGI 中间件,如以下代码段所示: http ://flask.pocoo.org/snippets/35/
( This Flask bug seems to confirm that that is the preferred way.) (这个 Flask 错误似乎证实这是首选方式。)
Basically, if your WSGI environment has environ['wsgi.url_scheme'] = 'https'
, then url_for
will generate https:
URLs.基本上,如果你的 WSGI 环境有 environment
environ['wsgi.url_scheme'] = 'https'
,那么url_for
将生成https:
URL。
I was getting http://
URLs from url_for
because my server was deployed behind an Elastic Beanstalk load balancer, which communicates with the server in regular HTTP.我从
url_for
获取http://
URL,因为我的服务器部署在 Elastic Beanstalk 负载均衡器后面,该负载均衡器以常规 HTTP 与服务器通信。 My solution (specific to Elastic Beanstalk) was like this (simplified from the snippet linked above):我的解决方案(特定于 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)
The Elastic Beanstalk-specific part of that is HTTP_X_FORWARDED_PROTO
.其中 Elastic Beanstalk 特定的部分是
HTTP_X_FORWARDED_PROTO
。 Other environments would have other ways of determining whether the external URL included https.其他环境有其他方法来确定外部 URL 是否包含 https。 If you just want to always use HTTPS, you could unconditionally set
environ['wsgi.url_scheme'] = 'https'
.如果您只想始终使用 HTTPS,则可以无条件地设置
environ['wsgi.url_scheme'] = 'https'
。
PREFERRED_URL_SCHEME
is not the way to do this. PREFERRED_URL_SCHEME
不是这样做的方法。 It's ignored whenever a request is in progress . 每当请求正在进行时,它就会被忽略。
I tried the accepted answer with an url_for
arg but I found it easier to use the PREFERRED_URL_SCHEME
config variable and set it to https with:我使用
url_for
arg 尝试了接受的答案,但我发现使用PREFERRED_URL_SCHEME
配置变量并将其设置为 https 更容易:
app.config.update(dict(
PREFERRED_URL_SCHEME = 'https'
))
since you don't have to add it to every url_for
call.因为您不必将它添加到每个
url_for
调用中。
If your are accessing your website through a reverse proxy like Nginx, then Flask correctly dectects the scheme being HTTP
.如果您通过像 Nginx 这样的反向代理访问您的网站,那么 Flask 会正确地检测到方案是
HTTP
。
Browser -----HTTPS----> Reverse proxy -----HTTP----> Flask
The easiest solution is to configure your reverse proxy to set the X-Forwarded-Proto
header.最简单的解决方案是配置反向代理以设置
X-Forwarded-Proto
标头。 Flask will automatically detect this header and manage scheme accordingly. Flask 将自动检测此标头并相应地管理方案。 There is a more detailed explanation in the Flask documentation under the Proxy Setups section .
Flask 文档中的 Proxy Setups 部分有更详细的解释。 For example, if you use Nginx, you will have to add the following line in your
location
block.例如,如果您使用 Nginx,则必须在
location
块中添加以下行。
proxy_set_header X-Forwarded-Proto $scheme;
As other mentionned, if you can't change the configuration of your proxy, you can either use the werkzeug ProxyFix or build your own fix as described in the documentation: http://flask.pocoo.org/docs/0.12/deploying/wsgi-standalone/#proxy-setups正如其他人提到的,如果您无法更改代理的配置,您可以使用 werkzeug ProxyFix 或按照文档中的说明构建您自己的修复程序: http ://flask.pocoo.org/docs/0.12/deploying/ wsgi-standalone/#proxy-setups
Setting _scheme
on every url_for()
call is extremely tedious, and PREFERRED_URL_SCHEME
doesn't seem to work.在每个
url_for()
调用上设置_scheme
非常乏味,而且PREFERRED_URL_SCHEME
似乎不起作用。 However, mucking with what the request's supposed scheme is at the WSGI level seems to successfully convince Flask to always construct HTTPS URLs:然而,在 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)
For anyone ending up here recently there is an official uwsgi fixer for this: https://stackoverflow.com/a/23504684/13777925对于最近在这里结束的任何人,都有一个官方的 uwsgi 修复程序: https ://stackoverflow.com/a/23504684/13777925
FWIW this still didn't work for me since the header wasn't being set correctly so I augmented the ReversedProxied middleware to prefer https if found thusly: 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)
Called as:称为:
app = flask.Flask(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app)
This way if you've set the environment var "PREFERRED_URL_SCHEME" explicitly or if the nginx/etc/proxy sets the X_FORWARDED_PROTO, it does the right thing.这样,如果您已经明确设置了环境变量“PREFERRED_URL_SCHEME”,或者如果 nginx/etc/proxy 设置了 X_FORWARDED_PROTO,它就会做正确的事情。
我个人无法使用此处的任何答案解决此问题,但发现只需在 flask run 命令的末尾添加--cert=adhoc
即可解决该问题。
flask run --host=0.0.0.0 --cert=adhoc
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.