[英]Flask url_for generating http URL instead of https
當用戶注銷時,我使用url_for
生成重定向 URL:
return redirect(url_for('.index', _external=True))
但是,當我將頁面更改為https連接時, url_for
仍然給我http 。
我想明確要求url_for
在 URL 的開頭添加https 。
你能指點我怎么改嗎? 我查看了 Flask 文檔,但運氣不佳。
使用 Flask 0.10,將有一個比包裝url_for
更好的解決方案。 如果您查看https://github.com/mitsuhiko/flask/commit/b5069d07a24a3c3a54fb056aa6f4076a0e7088c7 , _scheme
添加一個_scheme
參數。 這意味着您可以執行以下操作:
url_for('secure_thingy',
_external=True,
_scheme='https',
viewarg1=1, ...)
_scheme
設置 URL 方案,生成一個 URL,如https://..
而不是http://
。 但是,默認情況下 Flask 僅生成路徑(沒有主機或方案),因此您需要包含/secure_thingy
_external=True
以從/secure_thingy
轉到https://example.com/secure_thingy
。
但是,請考慮讓您的網站僅使用 HTTPS。 似乎您試圖僅對少數“安全”路由部分強制執行 HTTPS,但如果鏈接到安全頁面的頁面未加密,則無法確保您的 https-URL 不會更改。 這類似於混合內容。
如果您想影響所有服務器生成的 URL( url_for
和redirect
)的 URL 方案,而不必在每次調用時設置_scheme
,似乎“正確”的答案是使用 WSGI 中間件,如以下代碼段所示: http ://flask.pocoo.org/snippets/35/
(這個 Flask 錯誤似乎證實這是首選方式。)
基本上,如果你的 WSGI 環境有 environment environ['wsgi.url_scheme'] = 'https'
,那么url_for
將生成https:
URL。
我從url_for
獲取http://
URL,因為我的服務器部署在 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
不是這樣做的方法。 每當請求正在進行時,它就會被忽略。
我使用url_for
arg 嘗試了接受的答案,但我發現使用PREFERRED_URL_SCHEME
配置變量並將其設置為 https 更容易:
app.config.update(dict(
PREFERRED_URL_SCHEME = 'https'
))
因為您不必將它添加到每個url_for
調用中。
如果您通過像 Nginx 這樣的反向代理訪問您的網站,那么 Flask 會正確地檢測到方案是HTTP
。
Browser -----HTTPS----> Reverse proxy -----HTTP----> Flask
最簡單的解決方案是配置反向代理以設置X-Forwarded-Proto
標頭。 Flask 將自動檢測此標頭並相應地管理方案。 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
在每個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 ://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,它就會做正確的事情。
我個人無法使用此處的任何答案解決此問題,但發現只需在 flask run 命令的末尾添加--cert=adhoc
即可解決該問題。
flask run --host=0.0.0.0 --cert=adhoc
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.