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

Flask's SERVER_NAME, Unterdomänen und 404 Fehler

Die Einstellung Flask's SERVER_NAME kann zu 404 Fehlern führen, wenn Sie Subdomänen verwenden.

25 November 2020
In Flask
post main image
https://unsplash.com/@azhar93

Dies ist ein kurzer Beitrag über Flask und die config -Variable SERVER_NAME. Wie viele Entwickler bin ich in einem bestimmten Moment darauf gestoßen, und ich dachte, ich teile meine Geschichte. Hoffentlich wird dies einigen Kopfschmerzen ersparen.

Meine Webseiten müssen durch Eingabe der folgenden Adressen im Browser verfügbar sein:

  • https://example.com = 'without-www', und,
  • https://www.example.com = 'with-www'

Darüber hinaus hatte ich für diese Website beschlossen, dass die URLs in den generierten Seiten 'without-www' oder 'with-www' lauten müssen, je nachdem, wie die Anfrage-URL lautet. Dies bedeutet, dass, wenn ich tippe:

https://example.com/contact

es gibt keine Umleitung und alle Links auf der generierten Seite beginnen (scheinen zu beginnen) mit https://example.com. Oder, wenn ich tippe:

https://www.example.com/contact

es gibt keine Umleitung und alle Links auf der generierten Seite beginnen (scheinen zu beginnen) mit https://www.example.com.

Ich muss hinzufügen, dass dies nicht die beste Praxis ist und dass Sie immer ein einziges canonical name verwenden sollten, was bedeutet, dass Ihre Website entweder 'with-www' oder 'without-www' ist, und niemals beide! In einem nächsten Beitrag werde ich auf Einzelheiten dazu eingehen.

Jedenfalls funktionierte das oben Gesagte für alle meine Websites bis auf eine, nämlich diese Website. Vor Monaten war das noch kein Problem, aber nach einem größeren Code-Update änderte sich das plötzlich. Um 404 Fehler für die 'with-www'- Version zu vermeiden, habe ich dies schnell gelöst, indem ich Nginx 'with-www ' auf 'without-www' umleiten ließ. Und dann gab es noch dringendere andere Projekte, und Monate vergingen.

Kürzlich war ich dabei, meinen (ISPConfig) Server zu aktualisieren und dachte, ich versuche es noch einmal. Natürlich immer noch 404 Fehler für die 'with-www'- Version.

Ich nahm mir etwas Zeit und beschloss, die gleiche Situation auf meinem Entwicklungs-PC zu schaffen. Das bedeutete, die Zertifikate Letsencrypt auf meinen PC zu kopieren und die Entwicklungskonfiguration leicht zu modifizieren, indem FLASK_ENV auf 'production' und Entfernen der Umleitung von 'with-www' auf 'without-www' in Nginx. Ich verließ FLASK_DEBUG=True, damit ich Haltepunkte (Ausnahmen) in den Code Python setzen und sehen konnte, was vor sich ging.

Glücklicherweise habe ich die gleichen 404 Fehler beim Wechsel von 'without-www' zu 'with-www' auf meinem PC festgestellt. Dann, nach einiger Zeit, startete ich Flask neu, und nun funktionierte plötzlich die Version 'with-www', und die Version 'without-www' ergab 404 Fehler. Welche? Andersherum?

Bei der Suche im Internet nach 'Flask 404' stieß ich auf Seiten, siehe Links unten, die andeuteten, dass die config -Variable SERVER_NAME das Problem sein könnte.

Dann erinnerte ich mich daran, dass ich SERVER_NAME zu my config hinzugefügt hatte, als ich an Celery -Aufgaben arbeitete. Ich tat dies, weil ich dachte, es könnte nützlich sein, Jinja -Vorlagen mit url_for()-Verknüpfungen in einigen Aufgaben zu generieren. Später habe ich diese Idee verworfen. Die Aufgaben sollten unkompliziert sein und keinen Schnickschnack enthalten. Aber ich habe den Code SERVER_NAME nicht entfernt, weil alles gut lief, und nachdem ich die Umleitung in Nginx gesetzt hatte, gab es dringendere andere Projekte, was sonst neu ist.

Beschreibung der Ereignisse

Meine factory.py (__init__.py) sah so aus:

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
        ....

Hier erhalte ich SERVER_NAME aus der Anfrage, falls sie nicht gesetzt wurde. Das bedeutet, sobald config[SERVER_NAME] gesetzt ist, wird es nicht mehr aktualisiert. Wenn ich mit:

https://www.peterspython.com

dann wird SERVER_NAME gesetzt auf: www.peterspython.com. Aber wenn ich mit:

https://peterspython.com

dann wird SERVER_NAME auf gesetzt: peterspython.com.

In beiden Fällen config merkt sich die SERVER_NAME zwischen Anfragen (dieser Sitzung), wenn ich also eine funktionierende 'with-www'- URL in eine 'without-www' -URL ändere, dann erhalten wir die 404 Fehler, weil das Flask Routing ein falsches SERVER_NAME verwendet.

Das Verhalten von Flask's SERVER_NAME ist gut dokumentiert, aber es vollständig zu verstehen ist eine andere Sache. Mein Problem wird auch in dem Artikel "Dinge, die Sie über Flask wissen sollten SERVER_NAME" beschrieben, siehe Links unten:

Sobald Sie SERVER_NAME eingestellt haben, kann Flask nur Anfragen von einer einzigen Domäne bedienen und 404 für andere Domänen zurückgeben. Wenn SERVER_NAME = mydomain.com ist, wird die Anfrage von www.mydomain.com nicht bedient ...'.

Lösung

Die Lösung besteht natürlich darin, die Linie zu entfernen:

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

Dadurch wird bei jeder Anfrage immer die Variable SERVER_NAME config gesetzt. Oder noch besser (?), entfernen Sie diese Zeilen alle zusammen, weil ich SERVER_NAME nirgendwo verwende.

Zusammenfassung

An einer Stelle fügte ich die Variable config zu meinem Code hinzu und setzte diese Variable in before_request nur dann, wenn sie nicht bereits gesetzt war. Ich habe vergessen, dass meine Website sowohl mit den URLs 'with-www' als auch 'without-www' betrieben werden kann und dass die URLs Flask config zwischen Anfragen derselben Sitzung bestehen bleiben. Sobald ich dort ankam, war es leicht zu lösen.

Das wäre nie passiert, wenn ich eine einzige canonical name für meine Website gewählt hätte. Mit diesem canonical name hätte sich Flask nur entweder mit 'with-www' oder 'without-www' befassen müssen, aber niemals mit beiden. In einem nächsten Beitrag werde ich erklären, warum Ihr canonical name immer 'with-www' lauten sollte.

Wie auch immer, Lektionen gelernt ... wieder einmal.

Links / Impressum

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

Mehr erfahren

Flask

Einen Kommentar hinterlassen

Kommentieren Sie anonym oder melden Sie sich zum Kommentieren an.

Kommentare (2)

Eine Antwort hinterlassen

Antworten Sie anonym oder melden Sie sich an, um zu antworten.

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