37. Praxisübung: Version 17

Diese neue Version enthält folgende Änderungen:
- Sie wird auf einen Apache/Windows-Server portiert;
- Um diese Portierung durchzuführen, enthält Version 17 alle erforderlichen Abhängigkeiten im Ordner [impots/http-servers/12]. Beachten Sie, dass frühere Versionen ihre Abhängigkeiten aus verschiedenen Ordnern im gesamten [python-flask-2020]-Projekt bezogen haben;
37.1. Verschiebung der Anwendungsabhängigkeiten

Beachten Sie, dass die Verwaltung der Anwendungsabhängigkeiten im Skript [syspath] erfolgt. In der vorherigen Version sah dieses Skript wie folgt aus:
Wir müssen alle Abhängigkeiten verschieben, deren absoluter Pfad von der Variablen [root_dir] in Zeile 8 abhängt, d. h. die Zeilen 13–26.
Das Skript [syspath] für die neue Version sieht wie folgt aus:
- Zeilen 8–27: Alle Abhängigkeiten beziehen sich nun auf die Variable [script_dir] in Zeile 5;
- Zeilen 42–45: Die Variable [root_dir] wurde aus der syspath-Konfiguration entfernt;
- Zeile 10: Die Anwendungsentitäten befinden sich im Ordner [entities] [1];
- Zeile 12: Die [dao]-Ebene befindet sich im Ordner [layers/dao] [2];
- Zeile 14: Die [business]-Schicht befindet sich im Ordner [layers/business] [2];
- Zeile 16: Die Dienstprogramme [Logger, SendMail] befinden sich im Ordner [utilities] [3];
- Zeilen 29–40: Der Python-Pfad der Anwendung wird berechnet, ohne das Modul [myutils] zu importieren;

37.2. Tests
Zu diesem Zeitpunkt sollte Version 17 funktionieren. Überprüfen Sie dies.
37.3. Portierung einer Python/Flask-Anwendung auf einen Apache/Windows-Server
37.3.1. Quellen
Um eine Flask-Anwendung auf Apache/Windows zu portieren, musste ich im Internet recherchieren. Hier ist der Link, der mir den Einstieg erleichtert hat: [https://medium.com/@madumalt/flask-app-deployment-in-windows-apache-server-mod-wsgi-82e1cfeeb2ed];
Ich habe die Informationen aus diesem Link verwendet, mit Ausnahme der Apache-Serverkonfiguration. Dafür habe ich eine Beispielkonfiguration für den Apache-Server von Laragon verwendet.
37.3.2. Installation des Python-Moduls mod_wsgi
Die von uns entwickelte Python/Flask-Anwendung nutzte den in Flask enthaltenen WSGI-Server (Web Server Gateway Interface) [werkzeug]. Dieser Server wird |hier| beschrieben. Der Link [https://www.fullstackpython.com/wsgi-servers.html] beschreibt, wie WSGI-Server funktionieren. Es gibt verschiedene |WSGI-Server|. Einer davon ist der Apache-Server, der im WSGI-Modus läuft. Dies ist die hier gewählte Lösung, da Laragon, das wir installiert haben, einen Apache-Server enthält.
Damit der Apache-Server eine Python-Anwendung hosten kann, müssen wir das Python-Modul [mod_wsgi] installieren. Die Installation dieses Moduls ist knifflig, da sie eine C++-Kompilierung erfordert. Um die Installation erfolgreich abzuschließen, benötigen Sie einen Microsoft C++-Compiler. Eine einfache Lösung ist die Installation der neuesten Version von Visual Studio Community [https://visualstudio.microsoft.com/fr/vs/community/].
Wenn Sie Visual Studio ausschließlich für [mod_wsgi] benötigen, können Sie die Installation auf die C++-Umgebung beschränken:

Sobald der C++-Compiler installiert ist, wird das [mod_wsgi]-Modul in einem PyCharm-Terminal installiert:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\http-servers\11>SET MOD_WSGI_APACHE_ROOTDIR=C:\MyPrograms\laragon\bin\apache\httpd-2.4.35-win64-VC15
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\http-servers\11>pip install mod_wsgi
Collecting mod_wsgi
Using cached mod_wsgi-4.7.1.tar.gz (498 kB)
Using legacy setup.py install for mod-wsgi, since package 'wheel' is not installed.
Installing collected packages: mod-wsgi
Running setup.py install for mod-wsgi ... done
Successfully installed mod-wsgi-4.7.1
- Zeile 1: Wir legen den Wert der Umgebungsvariablen [MOD_WSGI_APACHE_ROOTDIR] fest. Dieser Wert gibt den Speicherort des Apache-Servers im Dateisystem an. Hier lautet dieser Speicherort [<laragon>\bin\apache\httpd-2.4.35-win64-VC15], wobei <laragon> der Laragon-Installationsordner ist. Sie können diesen Speicherort auf verschiedene Weise ermitteln. Hier ist ein Beispiel, das mit einer der Optionen von Laragon ermittelt wurde:

In [1-3] ist die Datei [httpd.conf] die Hauptkonfigurationsdatei für den Apache-Server. Die betreffende Datei wird dann in einem Texteditor geöffnet (im folgenden Beispiel Notepad++):

In [2] ist der Apache-Installationsordner der Teil, der der Zeichenfolge [conf\httpd.conf] vorangestellt ist.
Kehren wir nun zur Installation des Moduls [mod_wsgi] zurück:
- Zeilen 3–9: Installation des Moduls [mod_wsgi];
37.3.3. Konfiguration des Laragon-Apache-Servers
Wir werden den Laragon-Apache-Server konfigurieren. Wir beginnen mit seiner Hauptkonfigurationsdatei [httpd.conf]:

Wir gehen zum Ende der Datei [httpd.conf]:
…
IncludeOptional "C:/MyPrograms/laragon/etc/apache2/alias/*.conf"
IncludeOptional "C:/MyPrograms/laragon/etc/apache2/sites-enabled/*.conf"
Include "C:/MyPrograms/laragon/etc/apache2/httpd-ssl.conf"
Include "C:/MyPrograms/laragon/etc/apache2/mod_php.conf"
# python mod_wsgi
LoadModule wsgi_module "c:/data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages/mod_wsgi/server/mod_wsgi.cp38-win_amd64.pyd"
- Zeile 8 wurde am Ende der bestehenden [httpd.conf]-Datei hinzugefügt. Sie teilt dem Apache-Server mit, wo er eine Komponente des soeben installierten [mod_wsgi]-Moduls finden kann;
Eine einfache Möglichkeit, den Pfad für Zeile 8 zu ermitteln, besteht darin, den folgenden Befehl in einem PyCharm-Terminal auszuführen:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\impots\http-servers\11>mod_wsgi-express module-config
LoadModule wsgi_module "c:/data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages/mod_wsgi/server/mod_wsgi.cp38-win_amd64.pyd"
WSGIPythonHome "c:/data/st-2020/dev/python/cours-2020/python3-flask-2020/venv"
In einigen Dokumentationen wird angegeben, dass die Zeilen 2 und 3 am Ende der Datei [httpd.conf] hinzugefügt werden sollten. In meinem Fall verursachte die obige Zeile 3 einen Fehler (fehlendes [encodings]-Modul). Daher wurde sie nicht in die Datei [httpd.conf] aufgenommen. Es wurde nur Zeile 2 hinzugefügt. Die Bedeutungen der verschiedenen [mod_wsgi]-Modulparameter, die in Apache-Konfigurationsdateien verwendet werden können, sind |hier| beschrieben.
Als Nächstes aktivieren wir das HTTPS-Protokoll auf dem Apache-Server:

- In [1-4] aktivieren wir das HTTPS-Protokoll auf dem Apache-Server;
Ab sofort können wir [https://serveur/chemin]-URLs verwenden;
Um Apache für die Bereitstellung einer Flask-Anwendung zu konfigurieren, werden in dem oben genannten Link virtuelle Hosts verwendet. Laragon bietet ebenfalls Funktionen zur Verwaltung virtueller Hosts:

- In [1-3] weisen wir Laragon an, virtuelle Hosts automatisch zu erstellen;
Der nächste Schritt besteht darin, ein Webprojekt mit Laragon zu erstellen:
![]() |
![]() | ![]() |
- Erstellen Sie in [1-3] ein leeres PHP-Projekt;
- In [4-8] hat Laragon eine virtuelle Website namens [auto.projet-test.test] erstellt, die durch die Datei [auto.projet-test.test.conf] [8] im Ordner [sites-enabled] [7] konfiguriert ist. Dieser Ordner befindet sich unter [<laragon>\etc\apache2\sites-enabled], wobei [laragon] der Installationsordner von Laragon ist;
Auch wenn dies nicht Teil unserer aktuellen Aufgabe ist, möchten Sie vielleicht einen Blick auf die soeben erstellte Website [test-project] werfen:

- In [1-5] wurde ein leeres Projekt erstellt. Es handelt sich um ein PHP-Projekt, das sich im Ordner [<laragon>/www] befindet, wobei [laragon] der Laragon-Installationsordner ist;
Sehen wir uns nun die von Laragon generierte Datei [auto.projet-test.test.conf] im Ordner [<laragon>\etc\apache2\sites-enabled] an:
define ROOT "C:/MyPrograms/laragon/www/projet-test/"
define SITE "projet-test.test"
<VirtualHost *:80>
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:443>
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile C:/MyPrograms/laragon/etc/ssl/laragon.crt
SSLCertificateKeyFile C:/MyPrograms/laragon/etc/ssl/laragon.key
</VirtualHost>
- Zeile 1: das Stammverzeichnis des erstellten Projekts im Dateisystem;
- Zeile 2: Der Name des virtuellen Servers. URLs für diesen Server haben das Format [http(s)://test-project.test/path];
- Zeilen 4–12: Konfiguration der virtuellen Website für Port 80 (Zeile 4) und das HTTP-Protokoll;
- Zeilen 14–27: Konfiguration des virtuellen Hosts für Port 443 (Zeile 14) und das HTTPS-Protokoll;
Schauen wir uns an, wie ein virtueller Server funktioniert. Starten wir zunächst die Apache- und PHP-Server:

Anschließend rufen wir über einen Browser die URL [http://projet-test.test/] auf:

- in [1] die angeforderte URL;
- in [2] wurde das HTTP-Protokoll verwendet;
- in [3], da das Projekt [projet-test] leer ist, erhalten wir den Index seines Ordners (Liste seines Inhalts), einen leeren Index;
Nun fordern wir die sichere URL [https://projet-test.test/] an:

- In [1-2] erhalten wir dieselbe Antwort wie zuvor, jedoch unter Verwendung des HTTPS-Protokolls [1];
Durch die Erstellung des virtuellen Servers [test-project.test] wurde ein neuer Eintrag in der Datei [<windows>/system32/drivers/etc/hosts] erstellt:

# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost
127.0.0.1 projet-test.test #laragon magic!
- Zeile 23: Die IP-Adresse für den Namen [test-project.test] lautet 127.0.0.1, d. h. die Adresse von [localhost] (Zeile 20), dem lokalen Rechner. Wenn Sie also die URL [http://projet-test.test/chemin] in einen Browser eingeben, wird die Anfrage an die Adresse 127.0.0.1 auf Port 80 gesendet. Der Apache-Server auf dem lokalen Rechner (localhost) antwortet dann.
Sie fragen sich vielleicht, warum der Apache-Server bei der Eingabe der Anfrage [http://projet-test.test/] die Konfiguration aus der Datei [<laragon>\etc\apache2\sites-enabled\auto.projet-test.test.conf] verwendet:

Um dies zu verstehen, müssen wir uns ansehen, was der Browser bei dieser Anfrage an den Apache-Server sendet. Machen wir das mit Postman:

- In [1-3] senden wir eine HTTPS-Anfrage [1];
- in [4] zeigt Postman an, dass es das Sicherheitszertifikat nicht erkannt hat. Das HTTPS-Protokoll stellt eine verschlüsselte Verbindung zwischen dem Web-Client (hier Postman) und dem Apache-Server her. Diese verschlüsselte Verbindung wird durch Zertifikate hergestellt, die zwischen dem Client und dem Server ausgetauscht werden. Es ist der Server, der den Prozess zum Aufbau der verschlüsselten Verbindung initiiert, indem er ein Sicherheitszertifikat an den Client sendet. Damit dieses Zertifikat vom Client akzeptiert wird, muss es signiert sein – mit anderen Worten: von Unternehmen erworben werden, die zur Ausstellung von Sicherheitszertifikaten berechtigt sind. Als wir das HTTPS-Protokoll von Laragon aktiviert haben, hat Laragon das Sicherheitszertifikat selbst erstellt. Das Zertifikat wird dann als selbstsigniert bezeichnet. Die meisten Web-Clients geben eine Warnung aus, wenn sie ein selbstsigniertes Zertifikat erhalten. Genau das tut Postman in [4]. Die meisten Web-Clients bieten dann an, die Überprüfung des vom Server gesendeten Sicherheitszertifikats zu deaktivieren. Dies bietet Postman in [5] an;
Wir klicken auf den Link [5], um die SSL-Überprüfung (Secure Sockets Layer) zu deaktivieren. SSL/TLS (Transport Layer Security) ist ein Sicherheitsprotokoll, das einen sicheren Kommunikationskanal zwischen zwei Rechnern im Internet herstellt. Dies ist das Protokoll, das hier von Apache verwendet wird. Die Antwort lautet wie folgt:

Wir erhalten dieselbe Seite wie mit einem herkömmlichen Browser. Sehen wir uns nun den Client-Server-Dialog in der Postman-Konsole (Strg-Alt-C) an:
- Zeile 6: Der HTTP-Header [Host] gibt den Namen des Servers an, an den sich der Web-Client wendet. Dies ist das Prinzip hinter virtuellen Servern. Unter einer einzigen IP-Adresse (hier 127.0.0.1) kann ein Webserver mehrere Websites mit unterschiedlichen Namen hosten. Der HTTP-Header [Host] ermöglicht es dem Client anzugeben, welchen Server (hier den unter der Adresse 127.0.0.1) er anspricht;
Was macht Apache also?
Beim Start liest Apache alle Konfigurationsdateien, die sich im Verzeichnis [[<laragon>\etc\apache2\sites-enabled]] befinden:

Jede Konfigurationsdatei definiert einen virtuellen Server. In der Datei [auto.projet-test.test.conf] finden Sie beispielsweise die folgende Zeile:
define ROOT "C:/MyPrograms/laragon/www/projet-test/"
define SITE "projet-test.test"
…
Zeile 2 definiert den virtuellen Server [test-project.test]. Die Datei [auto.projet-test.test.conf] enthält die Konfiguration für diesen virtuellen Server. Da der Apache-Server beim Start alle Konfigurationsdateien im Ordner [<laragon>\etc\apache2\sites-enabled] liest, weiß er, dass ein virtueller Server namens [projet-test.test] existiert. Wenn er also die folgende HTTPS-Anfrage vom Postman-Client erhält:
Es erkennt, dass die Anfrage an den virtuellen Server [test-project.test] gerichtet ist (Zeile 6) und dass dieser existiert. Anschließend verwendet es die Konfiguration des virtuellen Servers [test-project.test], um dem Postman-Client zu antworten.
37.4. Erstellen Ihres ersten virtuellen Apache-Servers
Nachdem wir nun wissen, wozu virtuelle Server dienen und wie man sie konfiguriert, werden wir einen erstellen. Er wird dazu verwendet, eine Python-Flask-Anwendung auszuführen, die in einem [Apache]-Ordner der Version 17 installiert ist, die derzeit auf dem Apache-Server bereitgestellt wird:
Wir haben die im Abschnitt |link| entwickelte Anwendung – einen Webdienst für Datum und Uhrzeit – im Ordner [http-servers/12/apache/example] abgelegt:

Der Server [date_time_server.py] sieht wie folgt aus:
Die Flask-Anwendung wird durch den Bezeichner [application] referenziert (Zeilen 14, 43, 44). Dieser Name ist erforderlich. Wenn Sie die Flask-Anwendung mit einem anderen Bezeichner referenzieren, funktioniert die Anwendung nicht und zeigt eine Fehlermeldung an, die besagt, dass die angeforderte URL nicht gefunden werden kann. Diese Fehlermeldung gibt keinen Hinweis auf die Fehlerquelle. Sie müssen daher hier besonders vorsichtig sein.
Die in Zeile 34 referenzierte HTML-Datei lautet wie folgt:
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Date et heure du moment</title>
</head>
<body>
<b>Date et heure du moment : {{page.date_heure}}</b>
</body>
</html>
- [date-time-server] ist der virtuelle Server, auf dem diese Anwendung gehostet wird. Er wird über die Datei [<laragon>\etc\apache2\sites-enabled\date-time-server.conf] konfiguriert (beachten Sie, dass dieser Name beliebig ist – Apache liest alle Dateien in [sites-enabled], um die gehosteten virtuellen Sites zu ermitteln);
Wir erstellen diese Datei zunächst, indem wir die Datei [auto.projet-test.test.conf] kopieren und anschließend bearbeiten.

Die Datei [date-time-server.conf] sieht wie folgt aus:
- Zeile 7: Geben Sie dem durch die Datei konfigurierten virtuellen Server einen Namen;
- Zeile 2: Legt den Wert der Variablen [ROOT] fest, die in den Zeilen 14 und 27 verwendet wird;
- Zeilen 14 und 27: Geben Sie den Pfad zu dem Python-Skript an, das ausgeführt werden soll, wenn der virtuelle Server eine Anfrage erhält. Hier legen wir fest, dass Anfragen für den Server [date-time-server] vom Python-Skript [date_time_server.py] bearbeitet werden. Dieser Unterschied zur Datei [auto.projet-test.test.conf] ergibt sich daraus, dass in der erstgenannten Datei ein PHP-Server konfiguriert wurde, während die Datei [date-time-server.conf] einen Python-Server konfiguriert;
- Zeilen 14 und 27: Das Attribut [WSGIScriptAlias /] legt hier fest, dass das Stammverzeichnis des Servers [date-time-server] [/] ist. Somit haben die URLs der Anwendung die Form [http(s)://date-time-server/path];
- Zeilen 14 und 27: Wir können der Anwendung einen anderen Stammordner zuweisen, zum Beispiel [WSGIScriptAlias /show]. In diesem Fall haben die URLs der Anwendung die Form [http(s)://show/date-time-server/path];
Außerdem müssen wir eine Zeile zur Datei [<windows>/system32/drivers/etc/hosts] hinzufügen:
Wir fügen Zeile 25 hinzu, um dem virtuellen Server [date-time-server] die IP-Adresse [127.0.0.1] zuzuweisen.
Lassen Sie uns alles überprüfen. Wir starten den Apache-Server:

Als Nächstes rufen wir die URL [https://date-time-server] über einen Browser auf:
- in [1] die angeforderte URL;
- in [3] die Antwort des Servers;
- in [2] zeigt der Browser an, dass die HTTPS-Verbindung nicht sicher ist, da er festgestellt hat, dass das vom Apache-Server gesendete Zertifikat selbstsigniert ist;
Fügen wir nun in der Datei [date-time-server.conf] einen Alias zu den Zeilen 14 und 27 hinzu:
WSGIScriptAlias /show-date-time "${ROOT}/date_time_server.py"
Die Änderung wird vom Apache-Server nicht sofort erkannt. Sie müssen ihn neu laden:

Anschließend rufen wir die URL [https://date-time-server/show-date-time] auf. Die Antwort des Servers lautet wie folgt:

37.5. Portierung der Steuerberechnungsanwendung auf Apache / Windows
Das Verzeichnis [apache] [2] wird zunächst durch Kopieren des Verzeichnisses [main] erstellt. Es ist wichtig, dass sie sich auf derselben Ebene befinden, damit die Pfade im Skript [syspath.py], das von [1] nach [2] kopiert wurde, gültig bleiben. Um eine Beeinträchtigung der laufenden Anwendung [impots / http-servers/ 12] zu vermeiden, legen wir die vom Apache-Server auszuführende Konfiguration in [apache] ab;

- die [config]-Datei in [2] ist identisch mit der [config]-Datei in [1];
- die Datei [syspath] in [2] ist identisch mit der Datei [syspath] in [1];
- die Datei [main_withmysql] in [2] ist die Datei [main] aus [1] mit den folgenden Änderungen:
Das Hauptskript [main] erhielt einen [mysql / pgres]-Parameter, der angab, welches DBMS verwendet werden sollte. Das Skript [main_withmysql] verwendet das MySQL-DBMS:
In Zeile 7 wird das DBMS auf MySQL eingestellt.
- Die Datei [main_withpgres] aus [2] ist die Datei [main] aus [1] mit den folgenden Änderungen: Sie verwendet das DBMS PostgreSQL:
In Zeile 7 legen wir das DBMS auf PostgreSQL fest.
Sobald dies erledigt ist, erstellen wir das folgende Skript [main_withmysql.wsgi] (die verwendete Endung spielt keine Rolle):
Das Skript [main_withmysql.wsgi] ist das Ziel, das vom Apache-Server im WSGI-Modus ausgeführt wird:
- Das Ziel des Apache-Servers hätte auch das Skript [main_withmysql.py] sein können, wie es zuvor mit dem Skript [date_time_server.py] der Fall war. Dies hätte jedoch eine geringfügige Änderung erfordert:
- Anders als bei der Ausführung eines Konsolenskripts ist bei Apache das Verzeichnis, das das Ziel [main_withmysql.py] enthält, nicht Teil des Python-Pfads. Daher verursacht Zeile 6 des Skripts [main_withmysql.py] einen Fehler;
- die zweite Änderung, die notwendig gewesen wäre, besteht darin, dass in [main_withmysql] die Flask-Anwendung durch den Bezeichner [app] referenziert wird. Wir wissen, dass sie für Apache/WSGI auch durch einen Bezeichner [application] referenziert werden muss;
- Anstatt [main_withmysql.py] zu ändern, ändern wir das Apache-Ziel. Es ist nun das oben genannte Skript [main_withmysql.wsgi]:
- Zeilen 1–7: Wir fügen das Skriptverzeichnis zum Python-Pfad hinzu. Dadurch verursacht Zeile 6 von [main_withmysql.py] keinen Fehler mehr;
- Zeilen 9–10: Das Importieren von [main_withmysql.py] löst dessen Ausführung aus. Zusätzlich verweisen wir auf die Flask-Anwendung [app] in [main_withmysql.py] unter Verwendung des Bezeichners [application], der von Apache im WSGI-Modus benötigt wird;
Wir verfahren genauso mit dem Skript [main_withpgres.wsgi]:
Wir haben nun die ausführbaren Ziele für den Apache-Server. Jetzt müssen wir zwei virtuelle Server erstellen, einen für jedes Ziel.
In [<laragon>\etc\apache2\sites-enabled] erstellen wir die Datei [flask-imports-withmysql.conf] (der Name spielt keine Rolle):

# dossier du script .wsgi
define ROOT "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/impots/http-servers/12/apache"
# nom du site web configuré par ce fichier
# ici il s'appellera flask-impots-withmysql
# les URL seront du type http(s)://flask-impots-withmysql/path
define SITE "flask-impots-withmysql"
# mettre l'adresse IP 127.0.0.1 pour site SITE dans c:/windows/system32/drivers/etc/hosts
# mettre ici les chemins des bibliothèques Python à utiliser - les séparer par des virgules
# ici les bibliothèques d'un environnement virtuel Python
WSGIPythonPath "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages"
# Python Home - nécessaire uniquement s'il y a plusieurs versions de Python installées
# WSGIPythonHome "C:/Program Files/Python38"
# URL HTTP
<VirtualHost *:80>
# avec l'alias / les URL auront la forme /{prefixe_url}/action/...
# avec l'alias /impots les URL auront la forme /impots/{prefixe_url}/action/...
# où [prefixe_url] est défini dans parameters.py
WSGIScriptAlias / "${ROOT}/main_withmysql.wsgi"
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# URL sécurisées avec HTTPS
<VirtualHost *:443>
# avec l'alias / les URL auront la forme /{prefixe_url}/action/...
# avec l'alias /impots les URL auront la forme /impots/{prefixe_url}/action/...
# où [prefixe_url] est défini dans parameters.py
WSGIScriptAlias / "${ROOT}/main_withmysql.wsgi"
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile C:/MyPrograms/laragon/etc/ssl/laragon.crt
SSLCertificateKeyFile C:/myprograms/laragon/etc/ssl/laragon.key
</VirtualHost>
- Zeile 2: das Anwendungsverzeichnis, der von uns erstellte Ordner [apache];
- Zeilen 23, 38: das Ziel [main_withmysql.wsgi], das wir erstellt haben:
- Zeile 7: Der virtuelle Server erhält den Namen [flask-impots-withmysql];
- Zeile 13: Die Anweisung [WSGIPythonPath] ermöglicht es uns, Ordner zum Python-Pfad hinzuzufügen. Hier weiß Apache nicht, dass wir eine virtuelle Umgebung zur Entwicklung der Anwendung verwendet haben und dass sich alle von der Anwendung verwendeten Module in dieser virtuellen Umgebung befinden. Daher fügen wir in Zeile 13 den Ordner hinzu, der alle Module aus der verwendeten virtuellen Umgebung enthält. Eine Möglichkeit besteht darin, dieses Verzeichnis an einen anderen Ort im Dateisystem zu kopieren und auf diesen Ort zu verweisen. Eine andere Möglichkeit ist, dieses Verzeichnis direkt innerhalb des Ziels [main_withmysql.wsgi] zum Python-Pfad hinzuzufügen (dies ist wahrscheinlich die bessere Lösung);
- Zeile 16: Wir können Apache das Verzeichnis der Python-Installation im Dateisystem angeben. Normalerweise befindet sich dieses im PATH des Rechners, und oft ist diese Zeile überflüssig (was hier der Fall war). Es kann jedoch vorkommen, dass auf dem Rechner mehrere Python-Installationen vorhanden sind und die gewünschte nicht im PATH des Rechners enthalten ist. In diesem Fall löst diese Zeile das Problem;
Erstellen Sie auf ähnliche Weise eine Datei [flask-impots-withpgres.conf]:
# dossier du script .wsgi
define ROOT "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/impots/http-servers/12/apache"
# nom du site web configuré par ce fichier
# ici il s'appellera flask-impots-withmysql
# les URL seront du type http(s)://flask-impots-withmysql/path
define SITE "flask-impots-withpgres"
# mettre l'adresse IP 127.0.0.1 pour site SITE dans c:/windows/system32/drivers/etc/hosts
# mettre ici les chemins des bibliothèques Python à utiliser - les séparer par des virgules
# ici les bibliothèques d'un environnement virtuel Python
WSGIPythonPath "C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages"
# Python Home - nécessaire uniquement s'il y a plusieurs versions de Python installées
# WSGIPythonHome "C:/Program Files/Python38"
# URL HTTP
<VirtualHost *:80>
# avec l'alias / les URL auront la forme /{prefixe_url}/action/...
# avec l'alias /impots les URL auront la forme /impots/{prefixe_url}/action/...
# où [prefixe_url] est défini dans parameters.py
WSGIScriptAlias / "${ROOT}/main_withpgres.wsgi"
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# URL sécurisées avec HTTPS
<VirtualHost *:443>
# avec l'alias / les URL auront la forme /{prefixe_url}/action/...
# avec l'alias /impots les URL auront la forme /impots/{prefixe_url}/action/...
# où [prefixe_url] est défini dans parameters.py
WSGIScriptAlias / "${ROOT}/main_withpgres.wsgi"
DocumentRoot "${ROOT}"
ServerName ${SITE}
ServerAlias *.${SITE}
<Directory "${ROOT}">
AllowOverride All
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile C:/MyPrograms/laragon/etc/ssl/laragon.crt
SSLCertificateKeyFile C:/myprograms/laragon/etc/ssl/laragon.key
</VirtualHost>
Wir speichern alle diese Dateien, starten den Apache-Server sowie die MySQL- und PostgreSQL-Datenbanken. Die Anwendung ist in [configs/parameters.py] mit dem URL-Präfix [/do] und [with_csrftoken=False] (kein CSRF-Token) konfiguriert. Wir rufen die URL [https://flask-impots-withmysql/do] auf. Die Antwort des Servers lautet wie folgt:

Wir rufen nun die URL [https://flask-impots-pgres/do] auf. Die Antwort lautet wie folgt:

Beide Anwendungen funktionieren normal.
Ändern wir nun den Parameter [WSGIScriptAlias] in der Datei [flask-imports-withmysql.conf]:
- Zeilen 11 und 20, der WSI-Alias lautet nun [/impots];
Wir stoppen und starten den Apache-Server neu und rufen dann die URL [https://flask-impots-withmysql/impots/do] auf. Die Antwort des Servers lautet wie folgt:

Es kommt zu einem Absturz. Die URL [1] verrät uns die Ursache. Sie hätte [https://flask-impots-withmysql/impots/do/afficher-vue-authentification] lauten müssen. Der WSGI-Alias fehlt. Dies ist ein Fehler in unserer Anwendung. Sie weiß, wie man mit einem URL-Präfix umgeht (/do ist vorhanden). Man könnte meinen, dass das Hinzufügen des Präfixes [/imports/do] zu unserer Anwendung das vorherige Problem lösen würde. Aber nein. Wir stoßen dann auf andere Arten von Problemen. Der WSGI-Alias verhält sich nicht wie ein URL-Präfix.
Versuchen wir zu verstehen, was passiert ist. Wir haben die URL [https://flask-impots-withmysql/impots/do] aufgerufen. Wir erwarteten, die Authentifizierungsansicht zu sehen. In [1] oben sehen wir, dass die Anwendung die Anzeige angefordert hat, jedoch nicht mit der korrekten URL. Betrachten wir den Pfad der Anfrage [https://flask-impots-withmysql/impots/do].
Zunächst wurde die folgende Route (configs/routes.py) ausgeführt:
# les routes de l'application Flask
# racine de l'application
app.add_url_rule(f'{prefix_url}/', methods=['GET'],
view_func=routes.index)
Die Route in Zeile 3 lautet in unserem Beispiel [https://flask-impots-withmysql/impots/do]. Wir sehen, dass der Teil [https://flask-impots-withmysql/impots] aus der Route entfernt wurde, sodass nun einfach [/do] übrig bleibt. Was den Teil [https://flask-impots-withmysql] betrifft, so ist dies normal; der Servername ist nicht in der Route enthalten. Wir sehen jedoch, dass auch der WSGI-Alias [/imports] nicht enthalten ist. Dies ist ein wichtiger Punkt. Selbst mit einem WSGI-Alias bleiben unsere ursprünglichen Routen gültig.
Sehen wir uns nun an, was die Funktion [index] in Zeile 4 (configs/routes_without_csrftoken) bewirkt:
In Zeile 4 werden wir zur URL der Funktion [init_session] weitergeleitet. In [configs/routes.py] wurde diese Funktion der Route [/do/init-session/html] zugeordnet:
# init-session
app.add_url_rule(f'{prefix_url}/init-session/<string:type_response>{csrftoken_param}', methods=['GET'],
view_func=routes.init_session)
Zeile 2: In unserem Test ist [csrftoken_param] eine leere Zeichenkette. Die Anwendung verarbeitet hier kein CSRF-Token.
Die Funktion [init_session] ist wie folgt definiert (configs/routes_without_csrftoken):
Zeile 4: Wir starten die Aktionsverarbeitungskette [init-session]. Diese Kette endet wie folgt in [responses/HtmlResponse]:
…
# now it's time to generate the URL redirection, not forgetting the CSRF token if requested
if config['parameters']['with_csrftoken']:
csrf_token = f"/{generate_csrf()}"
else:
csrf_token = ""
# redirect response
return redirect(f"{config['parameters']['prefix_url']}{ads['to']}{csrf_token}"), status.HTTP_302_FOUND
Die Aktion [init-session] ist eine ADS-Aktion (Action Do Something), die mit einer Weiterleitung zu einer Ansicht endet (Zeile 9). Genau hier liegt das Problem. Die Funktion [redirect] in Zeile 9 fügt den WSGI-Alias nicht automatisch zur Weiterleitungs-URL hinzu. Dies ist im obigen Screenshot zu sehen. Der Alias /impots fehlt in der Weiterleitungs-URL.
Die folgende Version bietet eine Lösung für das WSGI-Alias-Problem.


