Dansk

En dybdegående udforskning af Tornado, et Python-webframework og asynkront netværksbibliotek. Lær at bygge skalerbare, højtydende applikationer med detaljerede forklaringer, eksempler og bedste praksis.

Tornado-dokumentation: En omfattende guide for udviklere verden over

Tornado er et Python-webframework og asynkront netværksbibliotek, oprindeligt udviklet hos FriendFeed. Det er særligt velegnet til long-polling, WebSockets og andre applikationer, der kræver en langvarig forbindelse til hver bruger. Dets ikke-blokerende netværks-I/O gør det ekstremt skalerbart og til et stærkt valg for at bygge højtydende webapplikationer. Denne omfattende guide vil føre dig gennem Tornados kernekoncepter og give praktiske eksempler, så du kan komme i gang.

Hvad er Tornado?

I sin kerne er Tornado et webframework og asynkront netværksbibliotek. I modsætning til traditionelle synkrone webframeworks bruger Tornado en enkelttrådet, event-loop-baseret arkitektur. Det betyder, at det kan håndtere mange samtidige forbindelser uden at kræve en tråd pr. forbindelse, hvilket gør det mere effektivt og skalerbart.

Nøglefunktioner i Tornado:

Opsætning af dit Tornado-miljø

Før du dykker ned i Tornado-udvikling, skal du opsætte dit miljø. Her er en trin-for-trin guide:

  1. Installer Python: Sørg for at have Python 3.6 eller nyere installeret. Du kan downloade det fra den officielle Python-hjemmeside (python.org).
  2. Opret et virtuelt miljø (anbefales): Brug venv eller virtualenv til at oprette et isoleret miljø til dit projekt:
    python3 -m venv myenv
    source myenv/bin/activate  # På Linux/macOS
    myenv\Scripts\activate  # På Windows
  3. Installer Tornado: Installer Tornado ved hjælp af pip:
    pip install tornado

Din første Tornado-applikation

Lad os oprette en simpel "Hello, World!"-applikation med Tornado. Opret en fil ved navn app.py og tilføj følgende kode:

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

Kør nu applikationen fra din terminal:

python app.py

Åbn din webbrowser og naviger til http://localhost:8888. Du skulle se beskeden "Hello, World!".

Forklaring:

Request-handlere og routing

Request-handlere er grundlaget for Tornado-webapplikationer. De definerer, hvordan indkommende HTTP-anmodninger skal håndteres baseret på URL'en. Routing mapper URL'er til specifikke request-handlere.

Definering af Request-handlere:

For at oprette en request-handler skal du nedarve fra tornado.web.RequestHandler og implementere de relevante HTTP-metoder (get, post, put, delete, etc.).

class MyHandler(tornado.web.RequestHandler):
 def get(self):
  self.write("Dette er en GET-anmodning.")

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

Routing:

Routing konfigureres, når tornado.web.Application oprettes. Du angiver en liste af tupler, hvor hver tuple indeholder et URL-mønster og den tilsvarende request-handler.

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

URL-mønstre:

URL-mønstre er regulære udtryk. Du kan bruge grupper i regulære udtryk til at fange dele af URL'en og sende dem som argumenter til request-handlerens metoder.

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

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

I dette eksempel matcher /user/([0-9]+) URL'er som /user/123. Delen ([0-9]+) fanger et eller flere cifre og sender dem som user_id-argumentet til get-metoden i UserHandler.

Templating

Tornado inkluderer en simpel og effektiv templating-motor. Skabeloner bruges til at generere HTML dynamisk, hvilket adskiller præsentationslogik fra applikationslogik.

Oprettelse af skabeloner:

Skabeloner gemmes typisk i separate filer (f.eks. index.html). Her er et simpelt eksempel:

<!DOCTYPE html>
<html>
<head>
 <title>Min Hjemmeside</title>
</head>
<body>
 <h1>Velkommen, {{ name }}!</h1>
 <p>I dag er det den {{ today }}.</p>
</body>
</html>

{{ name }} og {{ today }} er pladsholdere, der vil blive erstattet med faktiske værdier, når skabelonen renderes.

Rendering af skabeloner:

For at rendere en skabelon skal du bruge render()-metoden i din 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)

Sørg for, at template_path-indstillingen er konfigureret korrekt i dine applikationsindstillinger. Som standard leder Tornado efter skabeloner i en mappe ved navn templates i samme mappe som din applikationsfil.

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

Skabelon-syntaks:

Tornado-skabeloner understøtter forskellige funktioner, herunder:

Asynkrone operationer

Tornados styrke ligger i dets asynkrone kapabiliteter. Asynkrone operationer giver din applikation mulighed for at udføre ikke-blokerende I/O, hvilket forbedrer ydeevne og skalerbarhed. Dette er især nyttigt for opgaver, der involverer ventetid på eksterne ressourcer, såsom databaseforespørgsler eller netværksanmodninger.

@tornado.gen.coroutine:

@tornado.gen.coroutine-dekoratoren giver dig mulighed for at skrive asynkron kode ved hjælp af yield-nøgleordet. Dette får asynkron kode til at se ud og opføre sig mere som synkron kode, hvilket forbedrer læsbarheden og vedligeholdelsen.

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

I dette eksempel er http_client.fetch() en asynkron operation, der returnerer en Future. yield-nøgleordet suspenderer udførelsen af coroutinen, indtil Future er løst. Når Future er løst, genoptages coroutinen, og svar-body'en skrives til klienten.

tornado.concurrent.Future:

En Future repræsenterer resultatet af en asynkron operation, der måske endnu ikke er tilgængelig. Du kan bruge Future-objekter til at kæde asynkrone operationer sammen og håndtere fejl.

tornado.ioloop.IOLoop:

IOLoop er hjertet i Tornados asynkrone motor. Den overvåger fil-deskriptorer og sockets for hændelser og sender dem til de relevante handlere. Du behøver typisk ikke at interagere direkte med IOLoop, men det er vigtigt at forstå dens rolle i håndteringen af asynkrone operationer.

WebSockets

Tornado tilbyder fremragende understøttelse af WebSockets, hvilket muliggør realtidskommunikation mellem serveren og klienter. WebSockets er ideelle til applikationer, der kræver tovejskommunikation med lav latens, såsom chat-applikationer, online spil og realtids-dashboards.

Oprettelse af en WebSocket-handler:

For at oprette en WebSocket-handler skal du nedarve fra tornado.websocket.WebSocketHandler og implementere følgende metoder:

import tornado.websocket

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

 def on_message(self, message):
  self.write_message(f"Du sendte: {message}")

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

 def check_origin(self, origin):
  return True # Tillad cross-origin WebSocket-forbindelser

Integrering af WebSockets i din applikation:

Tilføj WebSocket-handleren til din applikations routing-konfiguration:

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

Klient-side implementering:

På klientsiden kan du bruge JavaScript til at etablere en WebSocket-forbindelse og sende/modtage beskeder:

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

websocket.onopen = () => {
 console.log("WebSocket-forbindelse etableret");
 websocket.send("Hej fra klienten!");
};

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

websocket.onclose = () => {
 console.log("WebSocket-forbindelse lukket");
};

Godkendelse og sikkerhed

Sikkerhed er et kritisk aspekt af udvikling af webapplikationer. Tornado tilbyder flere funktioner til at hjælpe dig med at sikre dine applikationer, herunder godkendelse, autorisation og beskyttelse mod almindelige web-sårbarheder.

Godkendelse:

Godkendelse er processen med at verificere en brugers identitet. Tornado tilbyder indbygget understøttelse af forskellige godkendelsesskemaer, herunder:

Autorisation:

Autorisation er processen med at afgøre, om en bruger har tilladelse til at tilgå en bestemt ressource. Du kan implementere autorisationslogik i dine request-handlere for at begrænse adgang baseret på brugerroller eller tilladelser.

Bedste praksis for sikkerhed:

Implementering

Implementering af en Tornado-applikation involverer flere trin, herunder konfiguration af en webserver, opsætning af en processtyring og optimering af ydeevnen.

Webserver:

Du kan implementere Tornado bag en webserver som Nginx eller Apache. Webserveren fungerer som en reverse proxy, der videresender indkommende anmodninger til Tornado-applikationen.

Processtyring:

En processtyring som Supervisor eller systemd kan bruges til at administrere Tornado-processen og sikre, at den automatisk genstartes, hvis den går ned.

Ydeevneoptimering:

Internationalisering (i18n) og lokalisering (l10n)

Når man bygger applikationer til et globalt publikum, er det vigtigt at overveje internationalisering (i18n) og lokalisering (l10n). i18n er processen med at designe en applikation, så den kan tilpasses forskellige sprog og regioner uden tekniske ændringer. l10n er processen med at tilpasse en internationaliseret applikation til et specifikt sprog eller en specifik region ved at tilføje lokalespecifikke komponenter og oversætte tekst.

Tornado og i18n/l10n

Tornado har ikke selv indbyggede i18n/l10n-biblioteker. Du kan dog nemt integrere standard Python-biblioteker som `gettext` eller mere sofistikerede frameworks som Babel til at håndtere i18n/l10n i din Tornado-applikation.

Eksempel med `gettext`:

1. **Opsæt dine locales:** Opret mapper for hvert sprog, du vil understøtte, som indeholder meddelelseskataloger (normalt `.mo`-filer).

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

2. **Udtræk oversættelige strenge:** Brug et værktøj som `xgettext` til at udtrække oversættelige strenge fra din Python-kode til en `.po`-fil (Portable Object). Denne fil vil indeholde de originale strenge og pladsholdere til oversættelser.

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

3. **Oversæt strengene:** Oversæt strengene i `.po`-filerne for hvert sprog.

4. **Kompiler oversættelserne:** Kompiler `.po`-filerne til `.mo`-filer (Machine Object), som bruges af `gettext` under kørsel.

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

5. **Integrer i din Tornado-applikation:**

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:
  # Håndter tilfælde, hvor sprogindstillingen ikke understøttes af systemet
  print(f"Sprogindstillingen {self.get_user_locale().code} er ikke understøttet")

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

 def get_current_user_locale(self):
  # Logik til at bestemme brugerens sprogindstilling (f.eks. fra Accept-Language header, brugerindstillinger osv.)
  # Dette er et forenklet eksempel - du får brug for en mere robust løsning
  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. **Rediger dine skabeloner:** Brug `_()`-funktionen (bundet til `gettext.gettext`) til at markere strenge til oversættelse i dine skabeloner.

<h1>{{ _("Velkommen til vores hjemmeside!") }}</h1>
<p>{{ _("Dette er et oversat afsnit.") }}</p>

Vigtige overvejelser for et globalt publikum:

Avancerede emner

Brugerdefinerede fejlsider:

Du kan tilpasse de fejlsider, som Tornado viser, når en fejl opstår. Dette giver dig mulighed for at levere en mere brugervenlig oplevelse og inkludere fejlfindingsoplysninger.

Brugerdefinerede indstillinger:

Du kan definere brugerdefinerede indstillinger i din applikationskonfiguration og få adgang til dem i dine request-handlere. Dette er nyttigt til at gemme applikationsspecifikke parametre, såsom databaseforbindelsesstrenge eller API-nøgler.

Testning:

Test dine Tornado-applikationer grundigt for at sikre, at de fungerer korrekt og sikkert. Brug enhedstests, integrationstests og end-to-end-tests til at dække alle aspekter af din applikation.

Konklusion

Tornado er et stærkt og alsidigt webframework, der er velegnet til at bygge skalerbare, højtydende webapplikationer. Dets asynkrone arkitektur, WebSocket-understøttelse og brugervenlige API gør det til et populært valg for udviklere verden over. Ved at følge retningslinjerne og eksemplerne i denne omfattende guide kan du begynde at bygge dine egne Tornado-applikationer og drage fordel af dets mange funktioner.

Husk at konsultere den officielle Tornado-dokumentation for de mest opdaterede oplysninger og bedste praksis. God kodning!