0%
Python côté Serveur : du CGI aux Applications WSGI Modernes

Python côté Serveur : du CGI aux Applications WSGI Modernes

Explorez l'évolution du développement web en Python : CGI, ses limites, WSGI, et la transition vers Flask/FastAPI pour des applications modernes et performantes.

I

InSkillCoach

· min

Python côté Serveur : du CGI aux Applications WSGI Modernes

L’interface Common Gateway Interface (CGI) a été la première façon de générer du contenu dynamique sur le web dans les années 1990. Bien que révolutionnaire à l’époque, CGI souffre de limitationsmajeure : chaque requête lance un nouveau processus Python, ce qui est inefficace et impossible à l’échelle. WSGI (Web Server Gateway Interface) a introduit un modèle plus efficace en 2003. Aujourd’hui, les frameworks WSGI comme Flask et les serveurs ASGI comme FastAPI dominent le paysage. Ce guide trace cette évolution et vous montre comment migrer du CGI vers les technologies modernes.

1. CGI : Les Origines

Qu’est-ce que CGI ?

CGI est un standard qui définit comment un serveur web (Apache, Nginx) exécute un programme externe (script CGI) pour traiter une requête HTTP et générer une réponse.

Le flux CGI :

  1. Client envoie une requête HTTP au serveur web
  2. Serveur web démarre un nouveau processus pour exécuter le script CGI
  3. Le script lit l’entrée (variables d’environnement, stdin)
  4. Le script génère une sortie (headers HTTP + body)
  5. Le serveur web renvoie la réponse au client
  6. Le processus se termine

Exemple minimal CGI

Supposons un serveur web configuré pour exécuter les scripts .cgi dans /cgi-bin/.

#!/usr/bin/env python
# Fichier : /cgi-bin/hello.cgi

import cgi
import cgitb

# Activer les rapports d'erreur CGI
cgitb.enable()

print("Content-Type: text/html; charset=utf-8")
print()

print("<html><body>")
print("<h1>Bonjour depuis CGI !</h1>")
print("</body></html>")

# Résultat : le serveur web envoie une réponse HTML au navigateur

Formulaire CGI avec traitement

#!/usr/bin/env python
# Fichier : /cgi-bin/form_handler.cgi

import cgi
import html

# Parser les données du formulaire
form = cgi.FieldStorage()
nom = form.getvalue("nom", "Visiteur inconnu")

# Échapper le contenu pour éviter les injections XSS
nom_safe = html.escape(nom)

print("Content-Type: text/html; charset=utf-8")
print()

print("<html><body>")
print(f"<h1>Bienvenue, {nom_safe} !</h1>")
print("</body></html>")

# Requête : GET /form_handler.cgi?nom=Alice
# Réponse : <h1>Bienvenue, Alice !</h1>

Limitations du CGI

LimitationImpact
Nouveau processus par requêteCoût de démarrage énorme ; impossible à l’échelle
Module cgi déprécié puis retiréDepuis Python 3.11, avec avertissement ; totalement supprimé en Python 3.13
Pas d’état persistantLes connexions à la base de données se réouvrent à chaque requête
Pas d’optimisationsPas de cache, pas de pool de workers, pas de concurrence
Sécurité à la charge du développeurPas de protection intégrée contre les injections, CSRF, etc.

2. WSGI : Un Modèle Meilleur

Qu’est-ce que WSGI ?

WSGI (PEP 3333) est une interface standardisée entre un serveur web et une application Python. Contrairement à CGI, l’application reste en mémoire entre les requêtes, ce qui élimine le coût de démarrage.

Une application WSGI est une fonction ou classe callable qui accepte deux arguments :

def application(environ, start_response):
    """
    environ : dictionnaire contenant les infos de la requête HTTP
    start_response : fonction pour envoyer les headers de réponse
    
    Retour : itérable de bytes (le body de la réponse)
    """
    status = "200 OK"
    response_headers = [("Content-Type", "text/html; charset=utf-8")]
    start_response(status, response_headers)
    
    body = "<html><body><h1>Bonjour WSGI !</h1></body></html>"
    return [body.encode("utf-8")]

# Résultat : application plus efficace que CGI

Exemple WSGI avec formulaire

from urllib.parse import parse_qs
import html

def app(environ, start_response):
    """Application WSGI simple avec traitement de formulaire."""
    
    method = environ["REQUEST_METHOD"]
    path = environ.get("PATH_INFO", "/")
    
    if method == "GET" and path == "/":
        # Page d'accueil avec formulaire
        body = """
        <html>
        <body>
            <h1>Entrez votre nom</h1>
            <form method="post" action="/submit">
                <input type="text" name="nom" required>
                <button type="submit">Envoyer</button>
            </form>
        </body>
        </html>
        """.encode("utf-8")
        
        start_response("200 OK", [("Content-Type", "text/html; charset=utf-8")])
        return [body]
    
    elif method == "POST" and path == "/submit":
        # Traiter les données du formulaire
        content_length = int(environ.get("CONTENT_LENGTH", 0))
        body = environ["wsgi.input"].read(content_length).decode("utf-8")
        data = parse_qs(body)
        nom = data.get("nom", ["Visiteur"])[0]
        nom_safe = html.escape(nom)
        
        response = f"<html><body><h1>Bonjour, {nom_safe} !</h1></body></html>".encode("utf-8")
        
        start_response("200 OK", [("Content-Type", "text/html; charset=utf-8")])
        return [response]
    
    else:
        start_response("404 Not Found", [("Content-Type", "text/plain")])
        return [b"Page non trouvée"]

# Exécuter avec wsgiref (serveur de développement inclus)
# python -m wsgiref.simple_server --port 8000 app:app
# Accédez à http://localhost:8000

Servir une application WSGI brute avec wsgiref

# Fichier : myapp.py

def app(environ, start_response):
    start_response("200 OK", [("Content-Type", "text/plain; charset=utf-8")])
    return [b"Hello from WSGI!"]

if __name__ == "__main__":
    from wsgiref.simple_server import make_server
    server = make_server("localhost", 8000, app)
    print("Serveur WSGI lancé sur http://localhost:8000")
    server.serve_forever()

# Exécution :
# python myapp.py
# Puis accédez à http://localhost:8000

3. http.server pour le Prototypage

Le module http.server de la stdlib offre un serveur HTTP simple, utile pour tester rapidement un prototype.

from http.server import HTTPServer, BaseHTTPRequestHandler
import json

class MonHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == "/":
            self.send_response(200)
            self.send_header("Content-Type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write(b"<h1>Accueil</h1>")
        elif self.path == "/api/info":
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            data = {"status": "ok", "message": "Réponse JSON"}
            self.wfile.write(json.dumps(data).encode("utf-8"))
        else:
            self.send_response(404)
            self.end_headers()
            self.wfile.write(b"Not found")

if __name__ == "__main__":
    server = HTTPServer(("localhost", 8000), MonHandler)
    print("Serveur lancé sur http://localhost:8000")
    server.serve_forever()

# Résultat : serveur simple mais sans cache, gestion d'erreur minimale, etc.

4. CGI vs WSGI vs ASGI : Comparaison

AspectCGIWSGIASGI
ProcessusNouveau par requêteUn processus persistantUn/plusieurs workers
ModèleSynchrone (bash/Perl/Python)Synchrone (Python)Asynchrone (async/await)
DémarrageTrès lent (fork OS)Rapide (fonction en mémoire)Rapide
Gestion d’étatImpossiblePossible (cache, BD)Possible
ScalabilitéMauvaiseBonneExcellente
FrameworksAucun (juste cgi)Flask, DjangoFastAPI, Starlette
Exemples d’usageHistorique (1990s)Blogs, MVPs, applications classiquesAPIs temps réel, WebSockets

5. Migration CGI vers Flask

Voici comment refactoriser un script CGI simple en Flask moderne.

Avant : CGI

#!/usr/bin/env python
# cgi-bin/calculator.cgi

import cgi

form = cgi.FieldStorage()
a = float(form.getvalue("a", 0))
b = float(form.getvalue("b", 0))
operation = form.getvalue("op", "add")

if operation == "add":
    result = a + b
elif operation == "subtract":
    result = a - b
else:
    result = 0

print("Content-Type: text/html; charset=utf-8")
print()
print(f"<h1>Résultat : {result}</h1>")

Après : Flask

# app.py

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/calculate", methods=["GET", "POST"])
def calculate():
    a = float(request.args.get("a", 0))
    b = float(request.args.get("b", 0))
    operation = request.args.get("op", "add")
    
    if operation == "add":
        result = a + b
    elif operation == "subtract":
        result = a - b
    else:
        result = 0
    
    # Répondre en JSON (moderne) au lieu d'HTML
    return jsonify({"a": a, "b": b, "operation": operation, "result": result})

if __name__ == "__main__":
    # pip install flask
    # python app.py
    # Accédez à http://localhost:5000/calculate?a=10&b=5&op=add
    app.run(debug=True, port=5000)

# Avantages :
# - Pas de parsing manuel
# - Réponse JSON structurée
# - Gestion d'erreur intégrée
# - Extensible facilement (middleware, templates, BD)

6. Bonnes Pratiques

  • Quittez CGI. Le module cgi est supprimé depuis Python 3.13. Aucune raison de rester dessus.
  • Choisissez un framework WSGI (Flask, Django) ou ASGI (FastAPI, Starlette). Ne codez pas de WSGI brut en production.
  • Utilisez un serveur applicatif : Gunicorn (WSGI) ou Uvicorn (ASGI), pas le serveur de développement.
  • Versionnez vos dépendances : pip freeze > requirements.txt ou utilisez Poetry/Pipenv.
  • Gérez l’état avec une base de données, pas en mémoire. Les workers sont stateless.
  • Testez votre application. Écrivez des tests unitaires et d’intégration.

Conclusion

Le CGI, bien qu’historique et élégant à son époque, est devenu obsolète. WSGI a apporté l’efficacité grâce à des processus persistants. Aujourd’hui, ASGI et des frameworks comme FastAPI poussent encore plus loin avec l’asynchrone et le support natif des WebSockets. Si vous maintenez du code CGI hérité, la migration vers Flask ou FastAPI est une étape importante pour maintenir la sécurité, la performance et la maintenabilité. Pour les nouveaux projets, partez directement de FastAPI pour bénéficier des standards modernes et des performances optimales.

InSkillCoach

À propos de InSkillCoach

Expert en formation et technologies

Coach spécialisé dans les technologies avancées et l'IA, porté par GNeurone Inc.

Certifications:

  • AWS Certified Solutions Architect – Professional
  • Certifications Google Cloud
  • Microsoft Certified: DevOps Engineer Expert
  • Certified Kubernetes Administrator (CKA)
  • CompTIA Security+
1.1k
210

Commentaires

Les commentaires sont alimentés par GitHub Discussions

Connectez-vous avec GitHub pour participer à la discussion

Lien copié !