37. Esercizio pratico: Versione 17

Questa nuova versione introduce le seguenti modifiche:
- sarà portata su un server Apache/Windows;
- Per eseguire questo porting, la versione 17 contiene tutte le dipendenze necessarie nella cartella [impots/http-servers/12]. Si noti che le versioni precedenti recuperavano le dipendenze da varie cartelle sparse nell'intero progetto [python-flask-2020];
37.1. Riorganizzazione delle dipendenze dell'applicazione

Si noti che la gestione delle dipendenze dell'applicazione è gestita nello script [syspath]. Nella versione precedente, questo script era il seguente:
Dobbiamo spostare tutte le dipendenze il cui percorso assoluto dipende dalla variabile [root_dir] alla riga 8, ovvero le righe 13–26.
Lo script [syspath] per la nuova versione sarà il seguente:
- righe 8–27: tutte le dipendenze sono ora relative alla variabile [script_dir] alla riga 5;
- righe 42–45: la variabile [root_dir] è stata rimossa dalla configurazione syspath;
- riga 10: le entità dell'applicazione si trovano nella cartella [entities] [1];
- riga 12: il livello [dao] si trova nella cartella [layers/dao] [2];
- riga 14: il livello [business] si trova nella cartella [layers/business] [2];
- riga 16: le utility [Logger, SendMail] si trovano nella cartella [utilities] [3];
- righe 29–40: il Python Path dell'applicazione viene calcolato senza importare il modulo [myutils];

37.2. Test
A questo punto, la versione 17 dovrebbe funzionare. Verificalo.
37.3. Porting di un'applicazione Python/Flask su un server Apache/Windows
37.3.1. Fonti
Per trasferire un'applicazione Flask su Apache/Windows, ho dovuto cercare su Internet. Ecco il link che mi ha aiutato a iniziare: [https://medium.com/@madumalt/flask-app-deployment-in-windows-apache-server-mod-wsgi-82e1cfeeb2ed];
Ho utilizzato le informazioni di questo link tranne che per la configurazione del server Apache. Per quella, ho utilizzato una configurazione di esempio del server Apache da Laragon.
37.3.2. Installazione del modulo Python mod_wsgi
L'applicazione Python/Flask che abbiamo sviluppato utilizzava il server WSGI (Web Server Gateway Interface) [werkzeug] incluso in Flask. Questo server è descritto |qui|. Il link [https://www.fullstackpython.com/wsgi-servers.html] descrive come funzionano i server WSGI. Esistono vari |server WSGI|. Uno di questi è il server Apache in modalità WSGI. Questa è la soluzione adottata in questo caso perché Laragon, che abbiamo installato, include un server Apache.
Affinché il server Apache possa ospitare un'applicazione Python, è necessario installare il modulo Python [mod_wsgi]. L'installazione di questo modulo è complessa perché richiede una compilazione in C++. Per completare l'installazione con successo, è necessario un compilatore Microsoft C++. Una soluzione semplice consiste nell'installare l'ultima versione di Visual Studio Community [https://visualstudio.microsoft.com/fr/vs/community/].
Se non avete bisogno di Visual Studio per scopi diversi da [mod_wsgi], potete limitare l'installazione all'ambiente C++:

Una volta installato il compilatore C++, il modulo [mod_wsgi] viene installato in un terminale PyCharm:
(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
- Riga 1: Impostiamo il valore della variabile d'ambiente [MOD_WSGI_APACHE_ROOTDIR]. Questo valore indica la posizione del server Apache nel file system. In questo caso, la posizione è [<laragon>\bin\apache\httpd-2.4.35-win64-VC15], dove <laragon> è la cartella di installazione di Laragon. È possibile ottenere questa posizione in vari modi. Eccone una ottenuta utilizzando una delle opzioni di Laragon:

In [1-3], il file [httpd.conf] è il file di configurazione principale del server Apache. Il file in questione viene quindi aperto in un editor di testo (Notepad++ di seguito):

In [2], la cartella di installazione di Apache è la parte che precede la stringa [conf\httpd.conf].
Torniamo all'installazione del modulo [mod_wsgi]:
- Righe 3–9: installazione del modulo [mod_wsgi];
37.3.3. Configurazione del server Apache Laragon
Configureremo il server Apache Laragon. Iniziamo con il suo file di configurazione principale [httpd.conf]:

Andiamo alla fine del file [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"
- La riga 8 è stata aggiunta al file [httpd.conf] esistente alla fine del file. Indica al server Apache dove trovare un componente del modulo [mod_wsgi] che abbiamo appena installato;
Un modo semplice per ottenere il percorso per la riga 8 è eseguire il seguente comando in un terminale PyCharm:
(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"
Alcuni documenti indicano che le righe 2 e 3 dovrebbero essere aggiunte alla fine del file [httpd.conf]. Nel mio caso, la riga 3 sopra riportata ha causato un errore (modulo [encodings] mancante). Pertanto, non è stata inclusa nel file [httpd.conf]. È stata aggiunta solo la riga 2. I significati dei vari parametri del modulo [mod_wsgi] che possono essere utilizzati nei file di configurazione di Apache sono descritti |qui|.
Successivamente, abiliteremo il protocollo HTTPS sul server Apache:

- Nei punti [1-4], abilitiamo il protocollo HTTPS sul server Apache;
D'ora in poi, potremo utilizzare gli URL [https://serveur/chemin];
Per configurare Apache in modo che ospiti un'applicazione Flask, il link indicato |sopra| utilizza gli host virtuali. Anche Laragon offre funzionalità di gestione degli host virtuali:

- In [1-3], chiediamo a Laragon di creare automaticamente gli host virtuali;
Il passo successivo consiste nel creare un progetto web con Laragon:
![]() |
![]() | ![]() |
- In [1-3], creare un progetto PHP vuoto;
- In [4-8], Laragon ha creato un sito virtuale denominato [auto.projet-test.test] configurato dal file [auto.projet-test.test.conf] [8] nella cartella [sites-enabled] [7]. Questa cartella si trova in [<laragon>\etc\apache2\sites-enabled], dove [laragon] è la cartella di installazione di Laragon;
Sebbene questo non faccia parte di ciò che stiamo facendo in questo momento, potresti essere curioso di dare un'occhiata al sito web [test-project] che abbiamo appena creato:

- In [1-5] è stato creato un progetto vuoto. Si tratta di un progetto PHP situato nella cartella [<laragon>/www], dove [laragon] è la cartella di installazione di Laragon;
Ora esaminiamo il file [auto.projet-test.test.conf] generato da Laragon nella cartella [<laragon>\etc\apache2\sites-enabled]:
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>
- riga 1: la directory principale del progetto creato nel file system;
- riga 2: il nome del server virtuale. Gli URL per questo server avranno il formato [http(s)://test-project.test/path];
- righe 4–12: configurazione del sito virtuale per la porta 80 (riga 4) e il protocollo HTTP;
- righe 14–27: configurazione dell'host virtuale per la porta 443 (riga 14) e il protocollo HTTPS;
Vediamo come funziona un server virtuale. Per prima cosa, avviamo i server Apache e PHP:

Quindi, utilizzando un browser, richiediamo l'URL [http://projet-test.test/]:

- in [1], l'URL richiesto;
- in [2], è stato utilizzato il protocollo HTTP;
- in [3], poiché il progetto [projet-test] è vuoto, otteniamo l'indice della sua cartella (elenco dei suoi contenuti), un indice vuoto;
Ora richiediamo l'URL sicuro [https://projet-test.test/]:

- In [1-2], otteniamo la stessa risposta di prima, ma utilizzando il protocollo HTTPS [1];
La creazione del server virtuale [test-project.test] ha creato una nuova voce nel file [<windows>/system32/drivers/etc/hosts]:

# 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!
- Riga 23: L'indirizzo IP per il nome [test-project.test] è 127.0.0.1, ovvero l'indirizzo di [localhost] (riga 20), la macchina locale. Quindi, quando digiti l'URL [http://projet-test.test/chemin] in un browser, la richiesta viene inviata all'indirizzo 127.0.0.1 sulla porta 80. Il server Apache sulla macchina locale (localhost) risponde quindi.
Ci si potrebbe chiedere perché, quando si digita la richiesta [http://projet-test.test/], il server Apache utilizzi la configurazione dal file [<laragon>\etc\apache2\sites-enabled\auto.projet-test.test.conf]:

Per capirlo, dobbiamo vedere cosa invia il browser al server Apache quando effettua questa richiesta. Facciamolo con Postman:

- In [1-3], inviamo una richiesta HTTPS [1];
- in [4], Postman indica di non aver riconosciuto il certificato di sicurezza. Il protocollo HTTPS stabilisce una connessione crittografata tra il client web (in questo caso, Postman) e il server Apache. Questa connessione crittografata viene stabilita tramite certificati scambiati tra il client e il server. È il server che avvia il processo di stabilimento della connessione crittografata inviando un certificato di sicurezza al client. Affinché questo certificato venga accettato dal client, deve essere firmato, in altre parole, acquistato da aziende autorizzate a emettere certificati di sicurezza. Quando abbiamo abilitato il protocollo HTTPS di Laragon, Laragon ha creato il certificato di sicurezza autonomamente. Si dice quindi che il certificato sia autofirmato. La maggior parte dei client web emette un avviso quando riceve un certificato autofirmato. Questo è ciò che fa Postman in [4]. La maggior parte dei client web offre quindi la possibilità di disabilitare la verifica del certificato di sicurezza inviato dal server. Questo è ciò che offre Postman in [5];
Clicchiamo sul link [5] per disabilitare la verifica SSL (Secure Sockets Layer). SSL/TLS (Transport Layer Security) è un protocollo di sicurezza che crea un canale di comunicazione sicuro tra due macchine su Internet. Questo è il protocollo utilizzato qui da Apache. La risposta è la seguente:

Riceviamo la stessa pagina che vedremmo con un browser tradizionale. Ora diamo un'occhiata al dialogo client/server nella console di Postman (Ctrl-Alt-C):
- Riga 6: L'intestazione HTTP [Host] specifica il nome del server a cui si rivolge il client web. Questo è il principio alla base dei server virtuali. A un singolo indirizzo IP (qui 127.0.0.1), un server web può ospitare più siti web con nomi diversi. L'intestazione HTTP [Host] permette al client di specificare a quale server (qui, quello all'indirizzo 127.0.0.1) si sta rivolgendo;
Allora, cosa fa Apache?
All'avvio, Apache legge tutti i file di configurazione presenti nella directory [[<laragon>\etc\apache2\sites-enabled]]:

Ogni file di configurazione definisce un server virtuale. Ad esempio, nel file [auto.projet-test.test.conf], troverai la seguente riga:
define ROOT "C:/MyPrograms/laragon/www/projet-test/"
define SITE "projet-test.test"
…
La riga 2 definisce il server virtuale [test-project.test]. Il file [auto.projet-test.test.conf] è la configurazione di questo server virtuale. Poiché all'avvio legge tutti i file di configurazione nella cartella [<laragon>\etc\apache2\sites-enabled], il server Apache sa che esiste un server virtuale denominato [projet-test.test]. Pertanto, quando riceve la seguente richiesta HTTPS dal client Postman:
Riconosce che la richiesta è indirizzata al server virtuale [test-project.test] (riga 6) e che questo esiste. Utilizza quindi la configurazione del server virtuale [test-project.test] per rispondere al client Postman.
37.4. Creazione del primo server virtuale Apache
Ora che sappiamo a cosa servono i server virtuali e come configurarli, ne creeremo uno. Verrà utilizzato per eseguire un'applicazione Python Flask installata in una cartella [Apache] della versione 17 attualmente in fase di distribuzione sul server Apache:
Abbiamo inserito l'applicazione sviluppata nella sezione |link|—un servizio web di data/ora—nella cartella [http-servers/12/apache/example]:

Il server [date_time_server.py] è il seguente:
L'applicazione Flask è indicata dall'identificatore [application] (righe 14, 43, 44). Questo nome è obbligatorio. Se si fa riferimento all'applicazione Flask con un identificatore diverso, l'applicazione non funzionerà e visualizzerà un messaggio di errore indicando che non è in grado di trovare l'URL richiesto. Questo messaggio di errore non fornisce alcuna indicazione sulla causa dell'errore. È quindi necessario prestare attenzione a questo aspetto.
Il file HTML a cui si fa riferimento alla riga 34 è il seguente:
<!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] sarà il server virtuale che ospita questa applicazione. Verrà configurato tramite il file [<laragon>\etc\apache2\sites-enabled\date-time-server.conf] (si noti che questo nome è arbitrario: Apache legge tutti i file in [sites-enabled] per individuare i siti virtuali ospitati);
Per prima cosa otteniamo questo file copiando il file [auto.projet-test.test.conf] e poi lo modifichiamo.

Il file [date-time-server.conf] avrà questo aspetto:
- Riga 7: assegna un nome al server virtuale configurato dal file;
- riga 2: imposta il valore della variabile [ROOT] utilizzata alle righe 14 e 27;
- Righe 14 e 27: specificano il percorso dello script Python che deve essere eseguito quando il server virtuale riceve una richiesta. Qui specifichiamo che le richieste per il server [date-time-server] sono gestite dallo script Python [date_time_server.py]. Questa differenza rispetto al file [auto.projet-test.test.conf] deriva dal fatto che il primo configurava un server PHP, mentre il file [date-time-server.conf] configura un server Python;
- Righe 14 e 27: L'attributo [WSGIScriptAlias /] specifica qui che la radice del server [date-time-server] sarà [/]. Pertanto, gli URL dell'applicazione assumeranno la forma [http(s)://date-time-server/path];
- Righe 14 e 27: È possibile assegnare una radice diversa all'applicazione, ad esempio [WSGIScriptAlias /show]. In questo caso, gli URL dell'applicazione assumeranno la forma [http(s)://show/date-time-server/path];
Dobbiamo anche aggiungere una riga al file [<windows>/system32/drivers/etc/hosts]:
Aggiungiamo la riga 25 per assegnare l'indirizzo IP [127.0.0.1] al server virtuale [date-time-server].
Controlliamo tutto. Avviamo il server Apache:

Successivamente, richiediamo l'URL [https://date-time-server] utilizzando un browser:
- in [1], l'URL richiesto;
- in [3], la risposta del server;
- in [2], il browser indica che la connessione HTTPS non è sicura perché ha rilevato che il certificato inviato dal server Apache era autofirmato;
Ora, nel file [date-time-server.conf], aggiungiamo un alias alle righe 14 e 27:
WSGIScriptAlias /show-date-time "${ROOT}/date_time_server.py"
La modifica non viene riconosciuta immediatamente dal server Apache. È necessario ricaricarlo:

Quindi richiediamo l'URL [https://date-time-server/show-date-time]. La risposta del server è la seguente:

37.5. Porting dell'applicazione di calcolo delle imposte su Apache / Windows
La directory [apache] [2] viene inizialmente creata copiando la directory [main]. È importante che si trovino allo stesso livello in modo che i percorsi nello script [syspath.py] copiati da [1] a [2] rimangano validi. Per evitare di interferire con l'applicazione [impots / http-servers/ 12] in esecuzione, inseriamo la configurazione che dovrà essere eseguita dal server Apache in [apache];

- il file [config] in [2] è lo stesso del file [config] in [1];
- il file [syspath] in [2] è lo stesso del file [syspath] in [1];
- il file [main_withmysql] in [2] è il file [main] di [1] con le seguenti modifiche:
Lo script principale [main] riceveva un parametro [mysql / pgres] che gli indicava quale DBMS utilizzare. Lo script [main_withmysql] utilizza il DBMS MySQL:
La riga 7 imposta il DBMS su MySQL.
- Il file [main_withpgres] di [2] è il file [main] di [1] con le seguenti modifiche: utilizza il DBMS PostgreSQL:
Alla riga 7, impostiamo il DBMS su PostgreSQL.
Una volta fatto questo, creiamo il seguente script [main_withmysql.wsgi] (il suffisso utilizzato non ha importanza):
Lo script [main_withmysql.wsgi] sarà il target eseguito dal server Apache in modalità WSGI:
- L'obiettivo del server Apache avrebbe potuto essere lo script [main_withmysql.py], come è stato fatto in precedenza con lo script [date_time_server.py]. Ma ciò avrebbe richiesto una leggera modifica:
- a differenza di quando si esegue uno script da console, con Apache la directory contenente il target [main_withmysql.py] non fa parte del Python Path. Pertanto, la riga 6 dello script [main_withmysql.py] genera un errore;
- la seconda modifica che sarebbe stata necessaria è che in [main_withmysql], l'applicazione Flask è referenziata dall'identificatore [app]. Sappiamo che per Apache/WSGI, deve essere referenziata anche da un identificatore [application];
- Invece di modificare [main_withmysql.py], cambiamo il target di Apache. Ora sarà lo script [main_withmysql.wsgi] sopra riportato:
- righe 1–7: aggiungiamo la directory dello script al Python Path. Di conseguenza, la riga 6 di [main_withmysql.py] non causa più un errore;
- righe 9–10: l'importazione di [main_withmysql.py] ne avvia l'esecuzione. Inoltre, facciamo riferimento all'applicazione Flask [app] presente in [main_withmysql.py] utilizzando l'identificatore [application] richiesto da Apache in modalità WSGI;
Facciamo lo stesso con lo script [main_withpgres.wsgi]:
Ora disponiamo dei target eseguibili per il server Apache. Dobbiamo ora creare due server virtuali, uno per ciascun target.
Nella directory [<laragon>\etc\apache2\sites-enabled], creiamo il file [flask-imports-withmysql.conf] (il nome non ha importanza):

# 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>
- riga 2: la radice dell'applicazione, la cartella [apache] che abbiamo creato;
- righe 23, 38: il target [main_withmysql.wsgi] che abbiamo creato:
- riga 7: il server virtuale si chiamerà [flask-impots-withmysql];
- riga 13: la direttiva [WSGIPythonPath] ci permette di aggiungere cartelle al Python Path. Qui, Apache non sa che abbiamo usato un ambiente virtuale per sviluppare l'applicazione e che tutti i moduli usati dall'applicazione si trovano in quell'ambiente virtuale. Pertanto, alla riga 13, aggiungiamo la cartella contenente tutti i moduli dell'ambiente virtuale utilizzato. Un'opzione è quella di copiare questa directory in un'altra posizione nel file system e fare riferimento a quella posizione. Un'altra opzione è quella di aggiungere questa directory al Python Path direttamente all'interno del target [main_withmysql.wsgi] (questa è probabilmente una soluzione migliore);
- riga 16: possiamo indicare ad Apache la directory di installazione di Python nel file system. Di norma, questa si trova nel PATH del sistema e spesso questa riga non è necessaria (come in questo caso). Tuttavia, potrebbero esserci più installazioni di Python sul sistema e quella desiderata potrebbe non essere presente nel PATH. In tal caso, questa riga risolve il problema;
Allo stesso modo, creare un file [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>
Salviamo tutti questi file, avviamo il server Apache e i database MySQL e PostgreSQL. L'applicazione è configurata con il prefisso URL [/do] e [with_csrftoken=False] (nessun token CSRF) in [configs/parameters.py]. Richiediamo l'URL [https://flask-impots-withmysql/do]. La risposta del server è la seguente:

Ora richiediamo l'URL [https://flask-impots-pgres/do]. La risposta è la seguente:

Entrambe le applicazioni funzionano normalmente.
Ora modifichiamo il parametro [WSGIScriptAlias] nel file [flask-imports-withmysql.conf]:
- nelle righe 11 e 20, l'alias WSI è ora [/impots];
Arrestiamo e riavviamo il server Apache, quindi richiediamo l'URL [https://flask-impots-withmysql/impots/do]. La risposta del server è la seguente:

Si verifica un crash. L'URL [1] ci indica la causa. Avrebbe dovuto essere [https://flask-impots-withmysql/impots/do/afficher-vue-authentification]. Manca l'alias WSGI. Si tratta di un errore nella nostra applicazione. Essa sa come gestire un prefisso URL (/do è presente). Si potrebbe pensare che l'aggiunta del prefisso [/impots/do] alla nostra applicazione risolverebbe il problema precedente. Ma no. Ci imbattiamo quindi in altri tipi di problemi. L'alias WSGI non si comporta come un prefisso URL.
Proviamo a capire cosa è successo. Abbiamo richiesto l'URL [https://flask-impots-withmysql/impots/do]. Ci aspettavamo di vedere la vista di autenticazione. Nel punto [1] sopra, vediamo che l'applicazione ha richiesto di visualizzarla, ma non con l'URL corretto. Esaminiamo il percorso della richiesta [https://flask-impots-withmysql/impots/do].
In primo luogo, è stato eseguito il seguente percorso (configs/routes.py):
# les routes de l'application Flask
# racine de l'application
app.add_url_rule(f'{prefix_url}/', methods=['GET'],
view_func=routes.index)
Il percorso alla riga 3 è [https://flask-impots-withmysql/impots/do] nel nostro esempio. Possiamo notare che al percorso è stata rimossa la parte [https://flask-impots-withmysql/impots] per diventare semplicemente [/do]. Per quanto riguarda la parte [https://flask-impots-withmysql], questo è normale; il nome del server non è incluso nel percorso. Ma possiamo vedere che non include nemmeno l'alias WSGI [/imports]. Questo è un punto importante. Anche con un alias WSGI, i nostri percorsi iniziali rimangono validi.
Ora vediamo cosa fa la funzione [index] alla riga 4 (configs/routes_without_csrftoken):
Alla riga 4, veniamo reindirizzati all'URL della funzione [init_session]. Nel file [configs/routes.py], questa funzione è stata associata alla route [/do/init-session/html]:
# init-session
app.add_url_rule(f'{prefix_url}/init-session/<string:type_response>{csrftoken_param}', methods=['GET'],
view_func=routes.init_session)
Riga 2: Nel nostro test, [csrftoken_param] è una stringa vuota. L'applicazione non gestisce un token CSRF in questo caso.
La funzione [init_session] è definita come segue (configs/routes_without_csrftoken):
Riga 4: Avviamo la catena di elaborazione dell'azione [init-session]. Questa catena termina come segue 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
L'azione [init-session] è un'azione ADS (Action Do Something) che termina con un reindirizzamento a una vista, riga 9. È proprio qui che risiede il problema. La funzione [redirect] alla riga 9 non aggiunge automaticamente l'alias WSGI all'URL di reindirizzamento. Ciò è mostrato nello screenshot sopra. L'alias /impots manca dall'URL di reindirizzamento.
La versione seguente fornisce una soluzione al problema dell'alias WSGI.


