Nederlands

Een diepgaande verkenning van Tornado, een Python webframework en asynchrone netwerkbibliotheek. Leer hoe u schaalbare, high-performance applicaties bouwt met gedetailleerde uitleg, voorbeelden en best practices.

Tornado Documentatie: Een Uitgebreide Gids voor Ontwikkelaars Wereldwijd

Tornado is een Python webframework en asynchrone netwerkbibliotheek, oorspronkelijk ontwikkeld bij FriendFeed. Het is bijzonder geschikt voor long-polling, WebSockets en andere applicaties die een langdurige verbinding met elke gebruiker vereisen. De niet-blokkerende netwerk I/O maakt het extreem schaalbaar en een krachtige keuze voor het bouwen van high-performance webapplicaties. Deze uitgebreide gids leidt u door de kernconcepten van Tornado en biedt praktische voorbeelden om u op weg te helpen.

Wat is Tornado?

In de kern is Tornado een webframework en een asynchrone netwerkbibliotheek. In tegenstelling tot traditionele synchrone webframeworks, gebruikt Tornado een single-threaded, event-loop-gebaseerde architectuur. Dit betekent dat het veel gelijktijdige verbindingen kan afhandelen zonder een thread per verbinding te vereisen, wat het efficiënter en schaalbaarder maakt.

Belangrijkste Kenmerken van Tornado:

Uw Tornado-omgeving Opzetten

Voordat u begint met de ontwikkeling van Tornado, moet u uw omgeving opzetten. Hier is een stapsgewijze handleiding:

  1. Installeer Python: Zorg ervoor dat u Python 3.6 of hoger hebt geïnstalleerd. U kunt het downloaden van de officiële Python-website (python.org).
  2. Maak een Virtuele Omgeving (Aanbevolen): Gebruik venv of virtualenv om een geïsoleerde omgeving voor uw project te maken:
    python3 -m venv myenv
    source myenv/bin/activate  # Op Linux/macOS
    myenv\Scripts\activate  # Op Windows
  3. Installeer Tornado: Installeer Tornado met pip:
    pip install tornado

Uw Eerste Tornado-applicatie

Laten we een eenvoudige "Hello, World!"-applicatie maken met Tornado. Maak een bestand met de naam app.py en voeg de volgende code toe:

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()

Voer nu de applicatie uit vanaf uw terminal:

python app.py

Open uw webbrowser en navigeer naar http://localhost:8888. U zou het "Hello, World!"-bericht moeten zien.

Uitleg:

Request Handlers en Routing

Request handlers vormen de basis van Tornado-webapplicaties. Ze definiëren hoe inkomende HTTP-verzoeken moeten worden afgehandeld op basis van de URL. Routing koppelt URL's aan specifieke request handlers.

Request Handlers Definiëren:

Om een request handler te maken, subklasseer tornado.web.RequestHandler en implementeer de juiste HTTP-methoden (get, post, put, delete, etc.).

class MyHandler(tornado.web.RequestHandler):
 def get(self):
  self.write("This is a GET request.")

 def post(self):
  data = self.request.body.decode('utf-8')
  self.write(f"Received POST data: {data}")

Routing:

Routing wordt geconfigureerd bij het aanmaken van de tornado.web.Application. U geeft een lijst van tupels op, waarbij elk tupel een URL-patroon en de bijbehorende request handler bevat.

app = tornado.web.Application([
 (r"/", MainHandler),
 (r"/myhandler", MyHandler),
])

URL-patronen:

URL-patronen zijn reguliere expressies. U kunt groepen van reguliere expressies gebruiken om delen van de URL vast te leggen en deze als argumenten door te geven aan de methoden van de request handler.

class UserHandler(tornado.web.RequestHandler):
 def get(self, user_id):
  self.write(f"User ID: {user_id}")

app = tornado.web.Application([
 (r"/user/([0-9]+)", UserHandler),
])

In dit voorbeeld komt /user/([0-9]+) overeen met URL's zoals /user/123. Het deel ([0-9]+) legt een of meer cijfers vast en geeft deze als het user_id-argument door aan de get-methode van de UserHandler.

Templating

Tornado bevat een eenvoudige en efficiënte templating engine. Templates worden gebruikt om HTML dynamisch te genereren, waardoor presentatielogica wordt gescheiden van applicatielogica.

Templates Maken:

Templates worden doorgaans opgeslagen in afzonderlijke bestanden (bijv. index.html). Hier is een eenvoudig voorbeeld:

<!DOCTYPE html>
<html>
<head>
 <title>Mijn Website</title>
</head>
<body>
 <h1>Welkom, {{ name }}!</h1>
 <p>Vandaag is het {{ today }}.</p>
</body>
</html>

De {{ name }} en {{ today }} zijn placeholders die worden vervangen door de werkelijke waarden wanneer de template wordt gerenderd.

Templates Renderen:

Om een template te renderen, gebruikt u de render()-methode in uw request handler:

class TemplateHandler(tornado.web.RequestHandler):
 def get(self):
  name = "John Doe"
  today = "2023-10-27"
  self.render("index.html", name=name, today=today)

Zorg ervoor dat de template_path-instelling correct is geconfigureerd in uw applicatie-instellingen. Standaard zoekt Tornado naar templates in een map met de naam templates in dezelfde map als uw applicatiebestand.

app = tornado.web.Application([
 (r"/template", TemplateHandler),
], template_path="templates")

Template Syntaxis:

Tornado-templates ondersteunen verschillende functies, waaronder:

Asynchrone Operaties

De kracht van Tornado ligt in zijn asynchrone capaciteiten. Asynchrone operaties stellen uw applicatie in staat om niet-blokkerende I/O uit te voeren, wat de prestaties en schaalbaarheid verbetert. Dit is met name handig voor taken die wachten op externe bronnen, zoals databasequery's of netwerkverzoeken.

@tornado.gen.coroutine:

De @tornado.gen.coroutine-decorator stelt u in staat om asynchrone code te schrijven met het yield-sleutelwoord. Dit zorgt ervoor dat asynchrone code er meer uitziet en zich gedraagt als synchrone code, wat de leesbaarheid en onderhoudbaarheid verbetert.

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'))

In dit voorbeeld is http_client.fetch() een asynchrone operatie die een Future retourneert. Het yield-sleutelwoord schort de uitvoering van de coroutine op totdat de Future is opgelost. Zodra de Future is opgelost, wordt de coroutine hervat en wordt de response body naar de client geschreven.

tornado.concurrent.Future:

Een Future vertegenwoordigt het resultaat van een asynchrone operatie die mogelijk nog niet beschikbaar is. U kunt Future-objecten gebruiken om asynchrone operaties aan elkaar te koppelen en fouten af te handelen.

tornado.ioloop.IOLoop:

De IOLoop is het hart van Tornado's asynchrone engine. Het monitort bestandsdescriptoren en sockets op gebeurtenissen en stuurt deze door naar de juiste handlers. U hoeft doorgaans niet rechtstreeks met de IOLoop te communiceren, maar het is belangrijk om de rol ervan bij het afhandelen van asynchrone operaties te begrijpen.

WebSockets

Tornado biedt uitstekende ondersteuning voor WebSockets, waardoor real-time communicatie tussen de server en clients mogelijk wordt. WebSockets zijn ideaal voor applicaties die bidirectionele, lage-latentie communicatie vereisen, zoals chat-applicaties, online games en real-time dashboards.

Een WebSocket Handler Maken:

Om een WebSocket handler te maken, subklasseer tornado.websocket.WebSocketHandler en implementeer de volgende methoden:

import tornado.websocket

class WebSocketHandler(tornado.websocket.WebSocketHandler):
 def open(self):
  print("WebSocket geopend")

 def on_message(self, message):
  self.write_message(f"U stuurde: {message}")

 def on_close(self):
  print("WebSocket gesloten")

 def check_origin(self, origin):
  return True # Schakel cross-origin WebSocket-verbindingen in

WebSockets Integreren in uw Applicatie:

Voeg de WebSocket handler toe aan de routingconfiguratie van uw applicatie:

app = tornado.web.Application([
 (r"/ws", WebSocketHandler),
])

Client-Side Implementatie:

Aan de client-zijde kunt u JavaScript gebruiken om een WebSocket-verbinding op te zetten en berichten te verzenden/ontvangen:

const websocket = new WebSocket("ws://localhost:8888/ws");

websocket.onopen = () => {
 console.log("WebSocket-verbinding opgezet");
 websocket.send("Hallo vanaf de client!");
};

websocket.onmessage = (event) => {
 console.log("Bericht ontvangen:", event.data);
};

websocket.onclose = () => {
 console.log("WebSocket-verbinding gesloten");
};

Authenticatie en Beveiliging

Beveiliging is een cruciaal aspect van webapplicatieontwikkeling. Tornado biedt verschillende functies om u te helpen uw applicaties te beveiligen, waaronder authenticatie, autorisatie en bescherming tegen veelvoorkomende webkwetsbaarheden.

Authenticatie:

Authenticatie is het proces van het verifiëren van de identiteit van een gebruiker. Tornado biedt ingebouwde ondersteuning voor verschillende authenticatiemethoden, waaronder:

Autorisatie:

Autorisatie is het proces om te bepalen of een gebruiker toestemming heeft om toegang te krijgen tot een bepaalde bron. U kunt autorisatielogica implementeren in uw request handlers om de toegang te beperken op basis van gebruikersrollen of permissies.

Best Practices voor Beveiliging:

Deployment

Het deployen van een Tornado-applicatie omvat verschillende stappen, waaronder het configureren van een webserver, het opzetten van een procesmanager en het optimaliseren van de prestaties.

Webserver:

U kunt Tornado achter een webserver zoals Nginx of Apache deployen. De webserver fungeert als een reverse proxy, die inkomende verzoeken doorstuurt naar de Tornado-applicatie.

Procesmanager:

Een procesmanager zoals Supervisor of systemd kan worden gebruikt om het Tornado-proces te beheren, zodat het automatisch opnieuw wordt opgestart als het crasht.

Prestatieoptimalisatie:

Internationalisatie (i18n) en Lokalisatie (l10n)

Bij het bouwen van applicaties voor een wereldwijd publiek is het belangrijk om rekening te houden met internationalisatie (i18n) en lokalisatie (l10n). i18n is het proces van het ontwerpen van een applicatie zodat deze kan worden aangepast aan verschillende talen en regio's zonder technische wijzigingen. l10n is het proces van het aanpassen van een geïnternationaliseerde applicatie voor een specifieke taal of regio door landspecifieke componenten toe te voegen en tekst te vertalen.

Tornado en i18n/l10n

Tornado zelf heeft geen ingebouwde i18n/l10n-bibliotheken. U kunt echter eenvoudig standaard Python-bibliotheken zoals `gettext` of meer geavanceerde frameworks zoals Babel integreren om i18n/l10n binnen uw Tornado-applicatie af te handelen.

Voorbeeld met `gettext`:

1. **Stel uw locales in:** Maak mappen voor elke taal die u wilt ondersteunen, met daarin berichtencatalogi (meestal `.mo`-bestanden).

locales/
 en/LC_MESSAGES/messages.mo
 fr/LC_MESSAGES/messages.mo
 de/LC_MESSAGES/messages.mo

2. **Extraheer vertaalbare strings:** Gebruik een tool zoals `xgettext` om vertaalbare strings uit uw Python-code te extraheren naar een `.po`-bestand (Portable Object). Dit bestand bevat de originele strings en placeholders voor vertalingen.

xgettext -d messages -o locales/messages.po your_tornado_app.py

3. **Vertaal de strings:** Vertaal de strings in de `.po`-bestanden voor elke taal.

4. **Compileer de vertalingen:** Compileer de `.po`-bestanden naar `.mo`-bestanden (Machine Object) die tijdens runtime door `gettext` worden gebruikt.

msgfmt locales/fr/LC_MESSAGES/messages.po -o locales/fr/LC_MESSAGES/messages.mo

5. **Integreer in uw Tornado-applicatie:**

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:
  # Behandel gevallen waarin de locale niet wordt ondersteund door het systeem
  print(f"Locale {self.get_user_locale().code} niet ondersteund")

  translation = gettext.translation('messages', 'locales', languages=[self.get_user_locale().code])
  translation.install()
  self._ = translation.gettext

 def get_current_user_locale(self):
  # Logica om de locale van de gebruiker te bepalen (bijv. uit Accept-Language header, gebruikersinstellingen, etc.)
  # Dit is een vereenvoudigd voorbeeld - u heeft een robuustere oplossing nodig
  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. **Pas uw templates aan:** Gebruik de `_()`-functie (gekoppeld aan `gettext.gettext`) om strings voor vertaling in uw templates te markeren.

<h1>{{ _("Welkom op onze website!") }}</h1>
<p>{{ _("Dit is een vertaalde paragraaf.") }}</p>

Belangrijke Overwegingen voor een Wereldwijd Publiek:

Geavanceerde Onderwerpen

Aangepaste Foutpagina's:

U kunt de foutpagina's die Tornado weergeeft wanneer er een fout optreedt, aanpassen. Dit stelt u in staat om een gebruiksvriendelijkere ervaring te bieden en foutopsporingsinformatie op te nemen.

Aangepaste Instellingen:

U kunt aangepaste instellingen definiëren in uw applicatieconfiguratie en deze openen in uw request handlers. Dit is handig voor het opslaan van applicatiespecifieke parameters, zoals databaseverbindingsreeksen of API-sleutels.

Testen:

Test uw Tornado-applicaties grondig om ervoor te zorgen dat ze correct en veilig functioneren. Gebruik unit tests, integratietests en end-to-end tests om alle aspecten van uw applicatie te dekken.

Conclusie

Tornado is een krachtig en veelzijdig webframework dat zeer geschikt is voor het bouwen van schaalbare, high-performance webapplicaties. De asynchrone architectuur, WebSocket-ondersteuning en gebruiksvriendelijke API maken het een populaire keuze voor ontwikkelaars wereldwijd. Door de richtlijnen en voorbeelden in deze uitgebreide gids te volgen, kunt u beginnen met het bouwen van uw eigen Tornado-applicaties en profiteren van de vele functies.

Vergeet niet de officiële Tornado-documentatie te raadplegen voor de meest actuele informatie en best practices. Veel codeerplezier!