Flask 的 url_for 生成 http URL 而非 https
我在使用 url_for
来生成用户登出后的重定向网址:
return redirect(url_for('.index', _external=True))
但是,当我把页面改成 https 连接时,url_for
还是给我返回 http 的网址。
我想明确地让 url_for
在网址前面加上 https。
你能告诉我怎么改吗?我查了 Flask 的文档,但没有找到解决办法。
9 个回答
我试过用一个 url_for
参数的方法,但我发现使用 PREFERRED_URL_SCHEME
这个配置变量更简单。我把它设置成了 https,如下所示:
app.config.update(dict(
PREFERRED_URL_SCHEME = 'https'
))
这样你就不用在每次调用 url_for
时都加上这个参数了。
如果你想让所有服务器生成的链接(比如用到的 url_for
和 redirect
)都使用特定的URL格式,而不是每次都要单独设置 _scheme
,那么“正确”的做法是使用WSGI中间件,像下面这个代码片段那样:http://flask.pocoo.org/snippets/35/
(这个Flask的bug似乎也确认了这是推荐的做法。)
简单来说,如果你的WSGI环境中有 environ['wsgi.url_scheme'] = 'https'
,那么 url_for
生成的链接就会是 https:
开头的。
我之前从 url_for
得到的链接是 http://
开头的,因为我的服务器是在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
。其他环境可能会有不同的方法来判断外部链接是否包含https。如果你想始终使用HTTPS,可以直接设置 environ['wsgi.url_scheme'] = 'https'
。
PREFERRED_URL_SCHEME
不是实现这个功能的正确方法。它在请求进行时会被忽略。
在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://
。不过,Flask默认只生成路径(没有主机名或协议),所以你需要加上_external=True
,才能把/secure_thingy
变成https://example.com/secure_thingy
。
不过,建议你考虑让你的网站只使用HTTPS。看起来你是想对一些“安全”的路由部分强制使用HTTPS,但如果链接到安全页面的页面没有加密,就无法保证你的HTTPS链接不会被更改。这种情况类似于混合内容的问题。