Flask url_for генерации http-URL вместо https
Я использую url_for
для создания URL перенаправления, когда пользователь вышел из системы:
return redirect(url_for('.index', _external=True))
Однако, когда я изменил страницу на соединение https, url_for
все еще дает мне http.
Я хотел бы явно попросить url_for
добавить https в начале URL.
Можете ли вы указать мне, как это изменить? Я посмотрел на документы Flask, без удачи.
Ответы
Ответ 1
С 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 генерирует только пути (без хоста или схемы), поэтому вам нужно будет включить _external=True
чтобы перейти от /secure_thingy
к https://example.com/secure_thingy
.
Тем не менее, рассмотрите возможность сделать свой сайт только для HTTPS. Кажется, вы пытаетесь частично применить HTTPS только для нескольких "безопасных" маршрутов, но вы не можете гарантировать, что ваш https-URL не изменится, если страница, ссылающаяся на защищенную страницу, не зашифрована. Это похоже на смешанный контент.
Ответ 2
Если вы хотите повлиять на схему URL для всех URL-адресов, созданных сервером (url_for
и redirect
), вместо того, чтобы устанавливать _scheme
для каждого вызова, кажется, что "правильный" ответ заключается в использовании WSGI, как в этом фрагменте: http://flask.pocoo.org/snippets/35/
(Эта ошибка Flask, похоже, подтверждает, что это предпочтительный вариант.)
В принципе, если ваша среда WSGI имеет environ['wsgi.url_scheme'] = 'https'
, то url_for
будет генерировать URL https:
.
Я получал http://
URL-адреса от url_for
, потому что мой сервер был развернут за балансиром нагрузки 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)
Эластичная составляющая этого компонента - HTTP_X_FORWARDED_PROTO
. В других средах есть другие способы определения, включен ли внешний URL-адрес https. Если вы просто хотите всегда использовать HTTPS, вы можете безоговорочно установить environ['wsgi.url_scheme'] = 'https'
.
PREFERRED_URL_SCHEME
- это не способ сделать это. Он игнорируется всякий раз, когда выполняется запрос.
Ответ 3
Я попробовал принятый ответ с аргументом url_for
, но мне было проще использовать конфигурационную конфигурацию PREFERRED_URL_SCHEME
и установить ее в https с помощью:
app.config.update(dict(
PREFERRED_URL_SCHEME = 'https'
))
так как вам не нужно добавлять его к каждому вызову url_for
.
Ответ 4
Если вы обращаетесь к своему веб-сайту через обратный прокси-сервер, такой как 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-автономный/# прокси-расстановок
Ответ 5
Настройка _scheme
для каждого вызова url_for()
крайне утомительна, а PREFERRED_URL_SCHEME
, похоже, не работает. Тем не менее, ошибка в том, что предполагаемая схема запроса на уровне WSGI, похоже, успешно убеждает Flask всегда создавать URL-адреса HTTPS:
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)