簡體   English   中英

Flask url_for 生成 http URL 而不是 https

[英]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_forredirect )的 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM