Explorez Tornado, le framework web Python asynchrone. Créez des applications évolutives et performantes avec nos explications, exemples et bonnes pratiques.
Documentation Tornado : Un Guide Complet pour les Développeurs du Monde Entier
Tornado est un framework web Python et une bibliothèque de réseau asynchrone, initialement développé chez FriendFeed. Il est particulièrement adapté au long-polling, aux WebSockets et à d'autres applications qui nécessitent une connexion de longue durée avec chaque utilisateur. Ses E/S réseau non bloquantes le rendent extrêmement évolutif et un choix puissant pour créer des applications web haute performance. Ce guide complet vous présentera les concepts fondamentaux de Tornado et fournira des exemples pratiques pour vous aider à démarrer.
Qu'est-ce que Tornado ?
Au cœur de sa conception, Tornado est un framework web et une bibliothèque de réseau asynchrone. Contrairement aux frameworks web synchrones traditionnels, Tornado utilise une architecture mono-thread basée sur une boucle d'événements. Cela signifie qu'il peut gérer de nombreuses connexions simultanées sans nécessiter un thread par connexion, ce qui le rend plus efficace et évolutif.
Caractéristiques Clés de Tornado :
- Réseau Asynchrone : Le cœur de Tornado est construit autour des E/S asynchrones, lui permettant de gérer efficacement des milliers de connexions simultanées.
- Framework Web : Il inclut des fonctionnalités comme les gestionnaires de requêtes, le routage, les modèles (templating) et l'authentification, ce qui en fait un framework web complet.
- Support des WebSockets : Tornado offre un excellent support pour les WebSockets, permettant une communication en temps réel entre le serveur et les clients.
- Léger et Rapide : Conçu pour la performance, Tornado est léger et efficace, minimisant la surcharge et maximisant le débit.
- Facile à Utiliser : Malgré ses fonctionnalités avancées, Tornado est relativement facile à apprendre et à utiliser, avec une API claire et bien documentée.
Configurer Votre Environnement Tornado
Avant de plonger dans le développement avec Tornado, vous devez configurer votre environnement. Voici un guide étape par étape :
- Installer Python : Assurez-vous d'avoir Python 3.6 ou une version ultérieure d'installé. Vous pouvez le télécharger depuis le site officiel de Python (python.org).
- Créer un Environnement Virtuel (Recommandé) : Utilisez
venv
ouvirtualenv
pour créer un environnement isolé pour votre projet :python3 -m venv myenv source myenv/bin/activate # Sur Linux/macOS myenv\Scripts\activate # Sur Windows
- Installer Tornado : Installez Tornado en utilisant pip :
pip install tornado
Votre Première Application Tornado
Créons une simple application "Hello, World!" avec Tornado. Créez un fichier nommé app.py
et ajoutez le code suivant :
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, World!")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
Maintenant, exécutez l'application depuis votre terminal :
python app.py
Ouvrez votre navigateur web et naviguez vers http://localhost:8888
. Vous devriez voir le message "Hello, World!".
Explication :
tornado.ioloop
: La boucle d'événements principale qui gère les opérations asynchrones.tornado.web
: Fournit les composants du framework web, tels que les gestionnaires de requêtes et le routage.MainHandler
: Un gestionnaire de requêtes qui définit comment traiter les requêtes HTTP entrantes. La méthodeget()
est appelée pour les requêtes GET.tornado.web.Application
: Crée l'application Tornado, en associant des modèles d'URL aux gestionnaires de requêtes.app.listen(8888)
: Démarre le serveur, en écoutant les connexions entrantes sur le port 8888.tornado.ioloop.IOLoop.current().start()
: Démarre la boucle d'événements, qui traite les requêtes entrantes et gère les opérations asynchrones.
Gestionnaires de Requêtes et Routage
Les gestionnaires de requêtes sont le fondement des applications web Tornado. Ils définissent comment traiter les requêtes HTTP entrantes en fonction de l'URL. Le routage associe les URL à des gestionnaires de requêtes spécifiques.
Définir les Gestionnaires de Requêtes :
Pour créer un gestionnaire de requêtes, héritez de la classe tornado.web.RequestHandler
et implémentez les méthodes HTTP appropriées (get
, post
, put
, delete
, etc.).
class MyHandler(tornado.web.RequestHandler):
def get(self):
self.write("Ceci est une requête GET.")
def post(self):
data = self.request.body.decode('utf-8')
self.write(f"Données POST reçues : {data}")
Routage :
Le routage est configuré lors de la création de l'objet tornado.web.Application
. Vous fournissez une liste de tuples, où chaque tuple contient un modèle d'URL et le gestionnaire de requêtes correspondant.
app = tornado.web.Application([
(r"/", MainHandler),
(r"/myhandler", MyHandler),
])
Modèles d'URL :
Les modèles d'URL sont des expressions régulières. Vous pouvez utiliser des groupes d'expressions régulières pour capturer des parties de l'URL et les passer comme arguments aux méthodes du gestionnaire de requêtes.
class UserHandler(tornado.web.RequestHandler):
def get(self, user_id):
self.write(f"ID Utilisateur : {user_id}")
app = tornado.web.Application([
(r"/user/([0-9]+)", UserHandler),
])
Dans cet exemple, /user/([0-9]+)
correspond à des URL comme /user/123
. La partie ([0-9]+)
capture un ou plusieurs chiffres et les passe comme argument user_id
à la méthode get
du UserHandler
.
Modèles (Templating)
Tornado inclut un moteur de modèles simple et efficace. Les modèles sont utilisés pour générer du HTML dynamiquement, séparant la logique de présentation de la logique applicative.
Créer des Modèles :
Les modèles sont généralement stockés dans des fichiers séparés (par ex., index.html
). Voici un exemple simple :
<!DOCTYPE html>
<html>
<head>
<title>Mon Site Web</title>
</head>
<body>
<h1>Bienvenue, {{ name }} !</h1>
<p>Aujourd'hui, nous sommes le {{ today }}.</p>
</body>
</html>
Les {{ name }}
et {{ today }}
sont des balises de remplacement qui seront remplacées par des valeurs réelles lors du rendu du modèle.
Rendu des Modèles :
Pour effectuer le rendu d'un modèle, utilisez la méthode render()
dans votre gestionnaire de requêtes :
class TemplateHandler(tornado.web.RequestHandler):
def get(self):
name = "John Doe"
today = "2023-10-27"
self.render("index.html", name=name, today=today)
Assurez-vous que le paramètre template_path
est correctement configuré dans les paramètres de votre application. Par défaut, Tornado recherche les modèles dans un répertoire nommé templates
situé dans le même répertoire que votre fichier d'application.
app = tornado.web.Application([
(r"/template", TemplateHandler),
], template_path="templates")
Syntaxe des Modèles :
Les modèles Tornado prennent en charge diverses fonctionnalités, notamment :
- Variables :
{{ variable }}
- Flux de Contrôle :
{% if condition %} ... {% else %} ... {% end %}
,{% for item in items %} ... {% end %}
- Fonctions :
{{ function(argument) }}
- Inclusions :
{% include "another_template.html" %}
- Échappement : Tornado échappe automatiquement les entités HTML pour prévenir les attaques de type cross-site scripting (XSS). Vous pouvez désactiver l'échappement en utilisant
{% raw variable %}
.
Opérations Asynchrones
La force de Tornado réside dans ses capacités asynchrones. Les opérations asynchrones permettent à votre application d'effectuer des E/S non bloquantes, améliorant ainsi les performances et la scalabilité. C'est particulièrement utile pour les tâches qui impliquent d'attendre des ressources externes, comme des requêtes de base de données ou des requêtes réseau.
@tornado.gen.coroutine
:
Le décorateur @tornado.gen.coroutine
vous permet d'écrire du code asynchrone en utilisant le mot-clé yield
. Cela rend le code asynchrone plus semblable au code synchrone en termes d'apparence et de comportement, améliorant la lisibilité et la maintenabilité.
import tornado.gen
import tornado.httpclient
class AsyncHandler(tornado.web.RequestHandler):
@tornado.gen.coroutine
def get(self):
http_client = tornado.httpclient.AsyncHTTPClient()
response = yield http_client.fetch("http://example.com")
self.write(response.body.decode('utf-8'))
Dans cet exemple, http_client.fetch()
est une opération asynchrone qui retourne un Future
. Le mot-clé yield
suspend l'exécution de la coroutine jusqu'à ce que le Future
soit résolu. Une fois le Future
résolu, la coroutine reprend et le corps de la réponse est écrit au client.
tornado.concurrent.Future
:
Un Future
représente le résultat d'une opération asynchrone qui n'est peut-être pas encore disponible. Vous pouvez utiliser les objets Future
pour enchaîner des opérations asynchrones et gérer les erreurs.
tornado.ioloop.IOLoop
:
L'IOLoop
est le cœur du moteur asynchrone de Tornado. Il surveille les descripteurs de fichiers et les sockets pour les événements et les distribue aux gestionnaires appropriés. En général, vous n'avez pas besoin d'interagir directement avec l'IOLoop
, mais il est important de comprendre son rôle dans la gestion des opérations asynchrones.
WebSockets
Tornado offre un excellent support pour les WebSockets, permettant une communication en temps réel entre le serveur et les clients. Les WebSockets sont idéaux pour les applications qui nécessitent une communication bidirectionnelle à faible latence, comme les applications de chat, les jeux en ligne et les tableaux de bord en temps réel.
Créer un Gestionnaire WebSocket :
Pour créer un gestionnaire WebSocket, héritez de la classe tornado.websocket.WebSocketHandler
et implémentez les méthodes suivantes :
open()
: Appelé lorsqu'une nouvelle connexion WebSocket est établie.on_message(message)
: Appelé lorsqu'un message est reçu du client.on_close()
: Appelé lorsque la connexion WebSocket est fermée.
import tornado.websocket
class WebSocketHandler(tornado.websocket.WebSocketHandler):
def open(self):
print("WebSocket ouvert")
def on_message(self, message):
self.write_message(f"Vous avez envoyé : {message}")
def on_close(self):
print("WebSocket fermé")
def check_origin(self, origin):
return True # Activer les connexions WebSocket cross-origin
Intégrer les WebSockets dans Votre Application :
Ajoutez le gestionnaire WebSocket à la configuration de routage de votre application :
app = tornado.web.Application([
(r"/ws", WebSocketHandler),
])
Implémentation Côté Client :
Côté client, vous pouvez utiliser JavaScript pour établir une connexion WebSocket et envoyer/recevoir des messages :
const websocket = new WebSocket("ws://localhost:8888/ws");
websocket.onopen = () => {
console.log("Connexion WebSocket établie");
websocket.send("Bonjour du client !");
};
websocket.onmessage = (event) => {
console.log("Message reçu :", event.data);
};
websocket.onclose = () => {
console.log("Connexion WebSocket fermée");
};
Authentification et Sécurité
La sécurité est un aspect critique du développement d'applications web. Tornado fournit plusieurs fonctionnalités pour vous aider à sécuriser vos applications, y compris l'authentification, l'autorisation et la protection contre les vulnérabilités web courantes.
Authentification :
L'authentification est le processus de vérification de l'identité d'un utilisateur. Tornado fournit un support intégré pour divers schémas d'authentification, notamment :
- Authentification par cookies : Stocker les informations d'identification de l'utilisateur dans des cookies.
- Authentification tierce (OAuth) : S'intégrer avec des plateformes de médias sociaux populaires comme Google, Facebook et Twitter.
- Clés d'API : Utiliser des clés d'API pour authentifier les requêtes API.
Autorisation :
L'autorisation est le processus qui consiste à déterminer si un utilisateur a la permission d'accéder à une ressource particulière. Vous pouvez implémenter la logique d'autorisation dans vos gestionnaires de requêtes pour restreindre l'accès en fonction des rôles ou des permissions des utilisateurs.
Bonnes Pratiques de Sécurité :
- Protection contre le Cross-Site Scripting (XSS) : Tornado échappe automatiquement les entités HTML pour prévenir les attaques XSS. Utilisez toujours la méthode
render()
pour le rendu des modèles et évitez de générer du HTML directement dans vos gestionnaires de requêtes. - Protection contre le Cross-Site Request Forgery (CSRF) : Activez la protection CSRF dans les paramètres de votre application pour prévenir les attaques CSRF.
- HTTPS : Utilisez toujours HTTPS pour chiffrer la communication entre le serveur et les clients.
- Validation des Entrées : Validez toutes les entrées utilisateur pour prévenir les attaques par injection et autres vulnérabilités.
- Audits de Sécurité Réguliers : Effectuez des audits de sécurité réguliers pour identifier et corriger les vulnérabilités potentielles.
Déploiement
Le déploiement d'une application Tornado implique plusieurs étapes, notamment la configuration d'un serveur web, la mise en place d'un gestionnaire de processus et l'optimisation des performances.
Serveur Web :
Vous pouvez déployer Tornado derrière un serveur web comme Nginx ou Apache. Le serveur web agit comme un reverse proxy, transmettant les requêtes entrantes à l'application Tornado.
Gestionnaire de Processus :
Un gestionnaire de processus comme Supervisor ou systemd peut être utilisé pour gérer le processus Tornado, assurant son redémarrage automatique en cas de plantage.
Optimisation des Performances :
- Utiliser une Boucle d'Événements Prête pour la Production : Utilisez une boucle d'événements prête pour la production comme
uvloop
pour de meilleures performances. - Activer la Compression gzip : Activez la compression gzip pour réduire la taille des réponses HTTP.
- Mettre en Cache les Fichiers Statiques : Mettez en cache les fichiers statiques pour réduire la charge sur le serveur.
- Surveiller les Performances : Surveillez les performances de votre application à l'aide d'outils comme New Relic ou Prometheus.
Internationalisation (i18n) et Localisation (l10n)
Lors de la création d'applications pour un public mondial, il est important de prendre en compte l'internationalisation (i18n) et la localisation (l10n). L'i18n est le processus de conception d'une application de manière à ce qu'elle puisse être adaptée à diverses langues et régions sans modifications techniques. La l10n est le processus d'adaptation d'une application internationalisée pour une langue ou une région spécifique en ajoutant des composants spécifiques à la locale et en traduisant le texte.
Tornado et i18n/l10n
Tornado lui-même n'a pas de bibliothèques i18n/l10n intégrées. Cependant, vous pouvez facilement intégrer des bibliothèques Python standard comme `gettext` ou des frameworks plus sophistiqués comme Babel pour gérer l'i18n/l10n au sein de votre application Tornado.
Exemple avec `gettext` :
1. **Configurez vos locales :** Créez des répertoires pour chaque langue que vous souhaitez prendre en charge, contenant des catalogues de messages (généralement des fichiers `.mo`).
locales/
en/LC_MESSAGES/messages.mo
fr/LC_MESSAGES/messages.mo
de/LC_MESSAGES/messages.mo
2. **Extrayez les chaînes traduisibles :** Utilisez un outil comme `xgettext` pour extraire les chaînes traduisibles de votre code Python dans un fichier `.po` (Portable Object). Ce fichier contiendra les chaînes originales et les emplacements pour les traductions.
xgettext -d messages -o locales/messages.po votre_app_tornado.py
3. **Traduisez les chaînes :** Traduisez les chaînes dans les fichiers `.po` pour chaque langue.
4. **Compilez les traductions :** Compilez les fichiers `.po` en fichiers `.mo` (Machine Object) qui sont utilisés par `gettext` à l'exécution.
msgfmt locales/fr/LC_MESSAGES/messages.po -o locales/fr/LC_MESSAGES/messages.mo
5. **Intégrez dans votre application Tornado :**
import gettext
import locale
import os
import tornado.web
class BaseHandler(tornado.web.RequestHandler):
def initialize(self):
try:
locale.setlocale(locale.LC_ALL, self.get_user_locale().code)
except locale.Error:
# Gérer les cas où la locale n'est pas supportée par le système
print(f"Locale {self.get_user_locale().code} non supportée")
translation = gettext.translation('messages', 'locales', languages=[self.get_user_locale().code])
translation.install()
self._ = translation.gettext
def get_current_user_locale(self):
# Logique pour déterminer la locale de l'utilisateur (ex: depuis l'en-tête Accept-Language, les paramètres utilisateur, etc.)
# Ceci est un exemple simplifié - vous aurez besoin d'une solution plus robuste
accept_language = self.request.headers.get('Accept-Language', 'en')
return tornado.locale.get(accept_language.split(',')[0].split(';')[0])
class MainHandler(BaseHandler):
def get(self):
self.render("index.html", _=self._)
settings = {
"template_path": os.path.join(os.path.dirname(__file__), "templates"),
}
app = tornado.web.Application([
(r"/", MainHandler),
], **settings)
6. **Modifiez vos modèles :** Utilisez la fonction `_()` (liée à `gettext.gettext`) pour marquer les chaînes à traduire dans vos modèles.
<h1>{{ _("Bienvenue sur notre site web !") }}</h1>
<p>{{ _("Ceci est un paragraphe traduit.") }}</p>
Considérations Importantes pour un Public Mondial :
- **Encodage des Caractères :** Utilisez toujours l'encodage UTF-8 pour supporter une large gamme de caractères.
- **Formatage de la Date et de l'Heure :** Utilisez un formatage de date et d'heure spécifique à la locale. Les fonctions `strftime` et `strptime` de Python peuvent être utilisées avec les paramètres de locale.
- **Formatage des Nombres :** Utilisez un formatage des nombres spécifique à la locale (par ex., séparateurs décimaux, séparateurs de milliers). Le module `locale` fournit des fonctions pour cela.
- **Formatage des Devises :** Utilisez un formatage de devise spécifique à la locale. Envisagez d'utiliser une bibliothèque comme `Babel` pour une gestion plus avancée des devises.
- **Langues de Droite à Gauche (RTL) :** Prenez en charge les langues RTL comme l'arabe et l'hébreu. Cela peut impliquer d'inverser la mise en page de votre site web.
- **Qualité de la Traduction :** Faites appel à des traducteurs professionnels pour garantir des traductions précises et culturellement appropriées. La traduction automatique peut être un bon point de départ, mais elle nécessite souvent une révision humaine.
- **Détection de la Locale Utilisateur :** Implémentez une détection de locale robuste basée sur les préférences de l'utilisateur, les paramètres du navigateur ou l'adresse IP. Fournissez un moyen pour les utilisateurs de sélectionner manuellement leur langue préférée.
- **Tests :** Testez minutieusement votre application avec différentes locales pour vous assurer que tout s'affiche correctement.
Sujets Avancés
Pages d'Erreur Personnalisées :
Vous pouvez personnaliser les pages d'erreur que Tornado affiche lorsqu'une erreur se produit. Cela vous permet de fournir une expérience plus conviviale et d'inclure des informations de débogage.
Paramètres Personnalisés :
Vous pouvez définir des paramètres personnalisés dans la configuration de votre application et y accéder dans vos gestionnaires de requêtes. C'est utile pour stocker des paramètres spécifiques à l'application, tels que les chaînes de connexion à la base de données ou les clés d'API.
Tests :
Testez minutieusement vos applications Tornado pour vous assurer qu'elles fonctionnent correctement et en toute sécurité. Utilisez des tests unitaires, des tests d'intégration et des tests de bout en bout pour couvrir tous les aspects de votre application.
Conclusion
Tornado est un framework web puissant et polyvalent, bien adapté pour créer des applications web évolutives et performantes. Son architecture asynchrone, son support des WebSockets et son API facile à utiliser en font un choix populaire pour les développeurs du monde entier. En suivant les directives et les exemples de ce guide complet, vous pouvez commencer à créer vos propres applications Tornado et tirer parti de ses nombreuses fonctionnalités.
N'oubliez pas de consulter la documentation officielle de Tornado pour les informations les plus à jour et les meilleures pratiques. Bon codage !