angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Flask SERVER_NAME, поддомены и 404 ошибки

Установка Flask в SERVER_NAME может дать 404 ошибки, если вы используете субдомены.

25 ноября 2020
В Flask
post main image
https://unsplash.com/@azhar93

Это короткий пост о Flask и config variable SERVER_NAME. Как и многие разработчики, я столкнулся с этим в определенный момент, и подумал, что могу поделиться своей историей. Надеюсь, для некоторых это предотвратит головную боль.

Мои сайты должны быть доступны, набрав в браузере следующие адреса:

  • https://example.com = 'without-www' и т.п,
  • https://www.example.com = 'with-www'

Более того, для этого сайта я решил, что URL в генерируемых страницах должны быть 'without-www' или 'with-www', в зависимости от того, какой URL запроса. Это означает, что если я набираю:

https://example.com/contact

переадресации нет и все ссылки в сгенерированной странице будут (выглядеть) начинаться с https://example.com. Или, если я набираю:

https://www.example.com/contact

переадресации нет и все ссылки в сгенерированной странице будут (выглядеть) начинаться с https://www.example.com.

Я должен добавить, что это не лучшая практика, и что вы всегда должны использовать один canonical name, что означает, что ваш сайт либо 'with-www', либо 'without-www', и никогда и то, и другое! В следующем посте я подробнее об этом расскажу.

В любом случае, вышесказанное отлично сработало для всех моих сайтов, кроме одного, этого сайта на самом деле. Месяцы назад это не было проблемой, но внезапно все изменилось после серьезного обновления кода. Чтобы не допустить 404 ошибки для версии 'with-www', я быстро решил эту проблему, попросив Nginx переадресовать 'with-www' на 'without-www'. А потом появились более срочные другие проекты и прошли месяцы.

Недавно я обновлял свой (ISPConfig) сервер и решил попробовать еще раз. Конечно, для версии 'with-www' все еще 404 ошибки.

Я потратил некоторое время и решил создать такую же ситуацию на моем ПК разработчика. Это означало копирование сертификатов Letsencrypt на мой ПК и слабовольное изменение конфигурации разработки путем изменения FLASK_ENV в 'production' и удаление перенаправления 'with-www' в 'without-www' в Nginx. Я оставил FLASK_DEBUG=True, чтобы в код Python можно было поместить точки останова (исключения) и посмотреть, что происходит.

К счастью, при смене 'without-www' на 'with-www' на моем компьютере я столкнулся с теми же самыми 404 ошибками. Затем, через некоторое время я перезапустил Flask и вдруг версия 'with-www' заработала, а версия 'without-www' дала 404 ошибки. Что? Наоборот?

В поисках в интернете 'Flask 404' я перепрыгнул на страницы, смотрите ссылки ниже, которые намекнули, что проблема может быть в config с переменной SERVER_NAME .

Затем я вспомнил, что добавлял SERVER_NAME к моей config , когда работал над задачами Celery . Я сделал это потому, что думал, что в некоторых задачах будет полезно генерировать шаблоны Jinja со ссылками url_for(). Позже я отбросил эту идею. Задачи должны быть простыми и не содержать колокольчиков и свистков. Но я не удалял код SERVER_NAME , потому что все работало нормально, и после установки перенаправления в Nginx появились более актуальные другие проекты, что еще новенького.

Описание того, что произошло

Моя фабрика. Пи (__init__.py) выглядела так:

def  create_app():
    ...
    @app.before_request
    def  before_request():
        ....
        # get server_name from  http_host
        if current_app.config.get('SERVER_NAME') is  None:
             http_host = request.environ.get('HTTP_HOST')
            current_app.config['SERVER_NAME'] =  http_host
        ....

Здесь я получаю SERVER_NAME из запроса, если он не был установлен. Это значит, что once config[SERVER_NAME] установлен и больше не обновляется. Если я начну с этого:

https://www.peterspython.com

тогда SERVER_NAME устанавливается на: www.peterspython.com. Но если я начну с этого:

https://peterspython.com

тогда SERVER_NAME будет установлен на значение SERVER_NAME : peterspython.com.

В обоих случаях config является членом SERVER_NAME между запросами (этой сессии), поэтому если я поменяю рабочий URL 'with-www' на URL 'without-www', то мы получаем ошибки 404, так как маршрутизация Flask использует неверный SERVER_NAME.

Поведение Flask's SERVER_NAME хорошо документировано, но полностью понимает это совсем другое. Моя проблема также описана в статье 'Вещи, которые вы должны знать о Flask SERVER_NAME', смотрите ссылки ниже:

'После установки SERVER_NAME, Flask может обслуживать запросы только с одного домена и возвращать 404 для других доменов. Если SERVER_NAME = mydomain.com, то он не будет обслуживать запрос от www.mydomain.com ...'.

Решение

Решение, конечно же, заключается в том, чтобы убрать линию:

        ....
        if current_app.config.get('SERVER_NAME') is  None:
        ....

Это всегда будет устанавливать переменную SERVER_NAME config vvariable при каждом запросе. Или еще лучше (?), удалите эти строки все вместе, потому что я нигде не использую SERVER_NAME .

Резюме

В какой-то момент я добавил в свой код переменную SERVER_NAME и установил эту переменную в before_request только тогда, когда она еще не была установлена. Я забыл, что мой сайт может работать как с URL 'with-www', так и с URL 'without-www', и что Flask config постоянно находится между запросами одной и той же сессии. Как только я добрался туда, это было легко решить.

Этого бы никогда не случилось, если бы я выбрал один canonical name для своего сайта. С этим canonical name Flask имел бы дело только с 'with-www' или 'without-www', но никогда не с тем и другим. В следующем посте я объясню, почему ваш canonical name всегда должен быть 'with-www'.

В любом случае, извлеченные уроки ... еще раз.

Ссылки / кредиты

SERVER_NAME configuration should not implicitly change routing behavior. #998
https://github.com/pallets/flask/issues/998

Things You Should Know About Flask SERVER_NAME
https://code.luasoftware.com/tutorials/flask/things-you-should-know-about-flask-server-name/

Unexplainable Flask 404 errors
https://stackoverflow.com/questions/24437248/unexplainable-flask-404-errors

Подробнее

Flask

Оставить комментарий

Комментируйте анонимно или войдите в систему, чтобы прокомментировать.

Комментарии (2)

Оставьте ответ

Ответьте анонимно или войдите в систему, чтобы ответить.

avatar

This has been clawing at me all afternoon. Thank you for sharing this.

avatar

A word of warning, changing the app config every before_request is sensitive to race conditions. So if you are using a threaded model of Flask execution, I would strongly advise against using the presented approach.
A small demo I tried to see if it would fit my needs in this gist: https://gist.github.com/eelkevdbos/14177eb9d72f5c96ed0f22ed64c30d19