- À propos du module http.server et ses usages
- Lancer un serveur de fichiers en une seule ligne
- Utiliser SimpleHTTPRequestHandler en programmation
- Créer un serveur personnalisé avec BaseHTTPRequestHandler
- Serveur avec gestion des paramètres d'URL et fichiers statiques
- Cas pratiques et extensions : multithreading et HTTPS
1. À propos du module http.server et ses usages
Le module http.server de Python fournit des classes pour implémenter des serveurs HTTP simples. Il fait partie de la bibliothèque standard, ce qui signifie qu'il est disponible sans installation supplémentaire. Ce module est idéal pour le développement local, le partage rapide de fichiers, les tests d'API, ou comme base pour construire des serveurs web plus complexes.
Les classes principales sont : HTTPServer (le serveur lui-même) et BaseHTTPRequestHandler (classe de base à hériter pour personnaliser les réponses). La classe SimpleHTTPRequestHandler permet de servir directement des fichiers depuis le répertoire courant.
2. Lancer un serveur de fichiers en une seule ligne
La manière la plus simple d'utiliser http.server est d'exécuter le module directement en ligne de commande. Cela lance un serveur qui sert les fichiers du répertoire courant sur le port 8000.
2.1 Serveur de fichiers simple en ligne de commande
La commande python -m http.server démarre instantanément un serveur HTTP. Il suffit d'ouvrir un navigateur à l'adresse http://localhost:8000 pour visualiser et télécharger les fichiers.
|
1 2 3 4 5 6 7 |
# Cette commande s'exécute dans le terminal, pas dans un script Python # python -m http.server 8000 # Sortie attendue dans le terminal : # Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... # 127.0.0.1 - - [25/Mar/2026 10:15:23] "GET / HTTP/1.1" 200 - # 127.0.0.1 - - [25/Mar/2026 10:15:23] "GET /favicon.ico HTTP/1.1" 404 - |
2.2 Serveur de fichiers avec port et adresse personnalisés
On peut spécifier le port et l'adresse d'écoute. L'utilisation de bind permet de rendre le serveur accessible sur le réseau local.
|
1 2 3 4 5 |
# Lancer sur le port 8080, accessible sur toutes les interfaces réseau # python -m http.server 8080 --bind 0.0.0.0 # Sortie : # Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ... |
3. Utiliser SimpleHTTPRequestHandler en programmation
Pour intégrer un serveur de fichiers dans un script Python, on utilise la classe SimpleHTTPRequestHandler avec HTTPServer. Cela permet de contrôler le comportement du serveur par programme.
3.1 Serveur de fichiers basique en script
Ce script crée un serveur HTTP qui sert les fichiers du répertoire courant. Le serveur tourne jusqu'à ce qu'on l'arrête avec Ctrl+C.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import http.server import socketserver PORT = 8000 # SimpleHTTPRequestHandler sert les fichiers du répertoire courant handler = http.server.SimpleHTTPRequestHandler with socketserver.TCPServer(("", PORT), handler) as httpd: print(f"Serveur démarré sur le port {PORT}") print(f"Accédez à http://localhost:{PORT}") print("Appuyez sur Ctrl+C pour arrêter") try: httpd.serve_forever() except KeyboardInterrupt: print("\nServeur arrêté") # Sortie : # Serveur démarré sur le port 8000 # Accédez à http://localhost:8000 # Appuyez sur Ctrl+C pour arrêter # ^C # Serveur arrêté |
3.2 Servir un répertoire spécifique
Pour servir un répertoire différent du répertoire courant, on peut changer le répertoire de travail avant de lancer le serveur ou créer un gestionnaire personnalisé.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
import http.server import socketserver import os # Changer temporairement le répertoire de travail REPERTOIRE_A_SERVIR = "/chemin/vers/mes/documents" PORT = 8000 original_dir = os.getcwd() try: os.chdir(REPERTOIRE_A_SERVIR) handler = http.server.SimpleHTTPRequestHandler with socketserver.TCPServer(("", PORT), handler) as httpd: print(f"Serveur du répertoire : {REPERTOIRE_A_SERVIR}") print(f"http://localhost:{PORT}") httpd.serve_forever() except KeyboardInterrupt: print("\nServeur arrêté") finally: os.chdir(original_dir) # Sortie : # Serveur du répertoire : /chemin/vers/mes/documents # http://localhost:8000 # ^C # Serveur arrêté |
4. Créer un serveur personnalisé avec BaseHTTPRequestHandler
Pour créer des endpoints personnalisés, on hérite de BaseHTTPRequestHandler et on surcharge les méthodes do_GET(), do_POST(), etc. Cela permet de construire des API simples ou des serveurs web dynamiques.
4.1 Serveur avec routes personnalisées
Cet exemple montre comment répondre différemment selon le chemin demandé. On utilise self.path pour récupérer l'URL demandée.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
import http.server import json class ServeurPersonnalise(http.server.BaseHTTPRequestHandler): def do_GET(self): if self.path == "/": self.envoyer_reponse_html(""" <html> <head><title>Serveur Python</title></head> <body> <h1>Bienvenue sur mon serveur personnalisé</h1> <ul> <li><a href="/api/hello">/api/hello</a> - Réponse JSON</li> <li><a href="/info">/info</a> - Informations serveur</li> </ul> </body> </html> """) elif self.path == "/api/hello": self.envoyer_reponse_json({"message": "Bonjour depuis Python!", "status": "success"}) elif self.path == "/info": self.envoyer_reponse_json({ "serveur": "Python http.server", "version": "1.0", "client": self.client_address[0] }) else: self.envoyer_erreur(404, "Page non trouvée") def envoyer_reponse_html(self, contenu): self.send_response(200) self.send_header("Content-type", "text/html; charset=utf-8") self.end_headers() self.wfile.write(contenu.encode("utf-8")) def envoyer_reponse_json(self, donnees): self.send_response(200) self.send_header("Content-type", "application/json") self.end_headers() self.wfile.write(json.dumps(donnees, indent=2).encode("utf-8")) def envoyer_erreur(self, code, message): self.send_response(code) self.send_header("Content-type", "text/plain") self.end_headers() self.wfile.write(f"Erreur {code}: {message}".encode("utf-8")) if __name__ == "__main__": import socketserver PORT = 8080 with socketserver.TCPServer(("", PORT), ServeurPersonnalise) as httpd: print(f"Serveur personnalisé démarré sur http://localhost:{PORT}") print("Routes disponibles: / , /api/hello , /info") httpd.serve_forever() # Sortie : # Serveur personnalisé démarré sur http://localhost:8080 # Routes disponibles: / , /api/hello , /info # 127.0.0.1 - - [25/Mar/2026 10:30:15] "GET /api/hello HTTP/1.1" 200 - # 127.0.0.1 - - [25/Mar/2026 10:30:20] "GET /info HTTP/1.1" 200 - |
4.2 Gestion des requêtes POST avec réception de données
Pour traiter les requêtes POST, on surcharge do_POST() et on lit le corps de la requête avec self.rfile.read(). Cela permet de créer des endpoints qui acceptent des données envoyées par un client.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
import http.server import json class ServeurAPI(http.server.BaseHTTPRequestHandler): def do_POST(self): if self.path == "/api/data": # Lire la longueur du corps de la requête longueur = int(self.headers.get("Content-Length", 0)) corps = self.rfile.read(longueur) try: # Tenter de parser le JSON reçu donnees = json.loads(corps.decode("utf-8")) # Traiter les données reponse = { "status": "reçu", "donnees_recues": donnees, "taille": len(corps) } self.send_response(200) self.send_header("Content-type", "application/json") self.end_headers() self.wfile.write(json.dumps(reponse, indent=2).encode("utf-8")) except json.JSONDecodeError: self.envoyer_erreur(400, "JSON invalide") else: self.envoyer_erreur(404, "Endpoint non trouvé") def do_GET(self): if self.path == "/": self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() self.wfile.write(b""" <html> <body> <h1>Test POST</h1> <form method="POST" action="/api/data"> <input type="text" name="nom" placeholder="Votre nom"> <button type="submit">Envoyer</button> </form> <pre>curl -X POST http://localhost:8080/api/data -H "Content-Type: application/json" -d '{"nom":"Python","version":3}'</pre> </body> </html> """) else: self.envoyer_erreur(404, "Page non trouvée") def envoyer_erreur(self, code, message): self.send_response(code) self.send_header("Content-type", "text/plain") self.end_headers() self.wfile.write(f"Erreur {code}: {message}".encode("utf-8")) if __name__ == "__main__": import socketserver PORT = 8080 with socketserver.TCPServer(("", PORT), ServeurAPI) as httpd: print(f"Serveur API démarré sur http://localhost:{PORT}") print("Endpoint POST disponible: /api/data") httpd.serve_forever() # Sortie : # Serveur API démarré sur http://localhost:8080 # Endpoint POST disponible: /api/data # 127.0.0.1 - - [25/Mar/2026 10:35:42] "POST /api/data HTTP/1.1" 200 - |
5. Serveur avec gestion des paramètres d'URL et fichiers statiques
On peut améliorer le serveur en analysant les paramètres d'URL (?key=value) et en servant des fichiers statiques comme des images, CSS ou JavaScript.
5.1 Analyse des paramètres d'URL
En utilisant urllib.parse, on peut extraire les paramètres d'une requête GET et y répondre dynamiquement.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
import http.server import urllib.parse import json class ServeurAvecParams(http.server.BaseHTTPRequestHandler): def do_GET(self): parsed = urllib.parse.urlparse(self.path) if parsed.path == "/api/calcul": # Extraire les paramètres params = urllib.parse.parse_qs(parsed.query) try: a = int(params.get("a", [0])[0]) b = int(params.get("b", [0])[0]) operation = params.get("op", ["somme"])[0] if operation == "somme": resultat = a + b elif operation == "produit": resultat = a * b elif operation == "difference": resultat = a - b else: resultat = "opération inconnue" reponse = { "a": a, "b": b, "operation": operation, "resultat": resultat } self.send_response(200) self.send_header("Content-type", "application/json") self.end_headers() self.wfile.write(json.dumps(reponse, indent=2).encode("utf-8")) except ValueError: self.envoyer_erreur(400, "Paramètres invalides, utilisez ?a=5&b=3&op=somme") else: super().do_GET() # Déléguer à SimpleHTTPRequestHandler pour les fichiers def envoyer_erreur(self, code, message): self.send_response(code) self.send_header("Content-type", "text/plain") self.end_headers() self.wfile.write(f"Erreur {code}: {message}".encode("utf-8")) if __name__ == "__main__": import socketserver PORT = 8080 # Mélanger personnalisation et fichiers statiques handler = type("Handler", (ServeurAvecParams, http.server.SimpleHTTPRequestHandler), {}) with socketserver.TCPServer(("", PORT), handler) as httpd: print(f"Serveur avec paramètres sur http://localhost:{PORT}") print("Exemples:") print(" http://localhost:8080/api/calcul?a=10&b=5&op=somme") print(" http://localhost:8080/api/calcul?a=7&b=3&op=produit") httpd.serve_forever() # Sortie : # Serveur avec paramètres sur http://localhost:8080 # Exemples: # http://localhost:8080/api/calcul?a=10&b=5&op=somme # http://localhost:8080/api/calcul?a=7&b=3&op=produit # 127.0.0.1 - - [25/Mar/2026 10:40:10] "GET /api/calcul?a=10&b=5&op=somme HTTP/1.1" 200 - |
6. Cas pratiques et extensions : multithreading et HTTPS
Pour gérer plusieurs clients simultanément, on utilise ThreadingTCPServer qui crée un nouveau thread pour chaque requête. On peut également ajouter le support HTTPS avec ssl.
6.1 Serveur multithread pour traiter plusieurs clients
La classe ThreadingTCPServer du module socketserver permet de traiter chaque requête dans un thread séparé, évitant ainsi les blocages.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import http.server import socketserver import threading class HandlerMultithread(http.server.SimpleHTTPRequestHandler): def log_message(self, format, *args): # Ajouter l'ID du thread pour le suivi thread_id = threading.current_thread().ident print(f"[Thread {thread_id}] {format % args}") PORT = 8000 # Utiliser ThreadingTCPServer au lieu de TCPServer with socketserver.ThreadingTCPServer(("", PORT), HandlerMultithread) as httpd: print(f"Serveur multithread sur http://localhost:{PORT}") print("Chaque requête est traitée dans un thread séparé") try: httpd.serve_forever() except KeyboardInterrupt: print("\nServeur arrêté") # Sortie : # Serveur multithread sur http://localhost:8000 # Chaque requête est traitée dans un thread séparé # [Thread 1234567890] "GET / HTTP/1.1" 200 - # [Thread 1234567891] "GET /style.css HTTP/1.1" 404 - |
6.2 Serveur HTTPS simple (auto-signé)
Pour ajouter le support SSL/TLS, on utilise le module ssl pour envelopper le socket du serveur. Cet exemple nécessite un certificat (créé avec openssl ou fourni).
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
import http.server import socketserver import ssl import os # Note : Ce code nécessite un certificat et une clé. # Pour générer un certificat auto-signé : # openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes PORT = 4443 CERTIFICAT = "cert.pem" CLE_PRIVEE = "key.pem" # Vérifier que les fichiers existent if not (os.path.exists(CERTIFICAT) and os.path.exists(CLE_PRIVEE)): print("Fichiers de certificat non trouvés.") print("Générez-les avec :") print("openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes") exit(1) handler = http.server.SimpleHTTPRequestHandler # Créer le serveur HTTP classique httpd = socketserver.TCPServer(("", PORT), handler) # Envelopper avec SSL context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) context.load_cert_chain(CERTIFICAT, CLE_PRIVEE) httpd.socket = context.wrap_socket(httpd.socket, server_side=True) print(f"Serveur HTTPS démarré sur https://localhost:{PORT}") print("Acceptez le certificat auto-signé dans votre navigateur") try: httpd.serve_forever() except KeyboardInterrupt: print("\nServeur arrêté") # Sortie : # Serveur HTTPS démarré sur https://localhost:4443 # Acceptez le certificat auto-signé dans votre navigateur # 127.0.0.1 - - [25/Mar/2026 10:50:23] "GET / HTTP/1.1" 200 - |
Auteur : Younes Derfoufi
Lieu de travail : CRMEF OUJDA
Site Web : www.tresfacile.net
Chaine YouTube : https://www.youtube.com/user/InformatiquesFacile
Me contacter : https://www.tresfacile.net/me-contacter/


