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:
- Asynkron netværkskommunikation: Tornados kerne er bygget op omkring asynkron I/O, hvilket gør det muligt at håndtere tusindvis af samtidige forbindelser effektivt.
- Webframework: Det inkluderer funktioner som request-handlere, routing, templating og godkendelse, hvilket gør det til et komplet webframework.
- WebSocket-understøttelse: Tornado tilbyder fremragende understøttelse af WebSockets, hvilket muliggør realtidskommunikation mellem serveren og klienter.
- Letvægt og hurtigt: Designet til ydeevne er Tornado let og effektivt, hvilket minimerer overhead og maksimerer gennemløb.
- Let at bruge: På trods af sine avancerede funktioner er Tornado relativt let at lære og bruge med et klart og veldokumenteret API.
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:
- Installer Python: Sørg for at have Python 3.6 eller nyere installeret. Du kan downloade det fra den officielle Python-hjemmeside (python.org).
- Opret et virtuelt miljø (anbefales): Brug
venv
ellervirtualenv
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
- 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:
tornado.ioloop
: Kerne-event-loopet, der håndterer asynkrone operationer.tornado.web
: Tilbyder webframework-komponenter, såsom request-handlere og routing.MainHandler
: En request-handler, der definerer, hvordan indkommende HTTP-anmodninger skal håndteres.get()
-metoden kaldes for GET-anmodninger.tornado.web.Application
: Opretter Tornado-applikationen og mapper URL-mønstre til request-handlere.app.listen(8888)
: Starter serveren, der lytter efter indkommende forbindelser på port 8888.tornado.ioloop.IOLoop.current().start()
: Starter event-loopet, som behandler indkommende anmodninger og håndterer asynkrone operationer.
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:
- Variabler:
{{ variable }}
- Kontrolflow:
{% if condition %} ... {% else %} ... {% end %}
,{% for item in items %} ... {% end %}
- Funktioner:
{{ function(argument) }}
- Inkluderinger:
{% include "another_template.html" %}
- Escaping: Tornado undslipper automatisk HTML-entiteter for at forhindre cross-site scripting (XSS)-angreb. Du kan deaktivere escaping ved hjælp af
{% raw variable %}
.
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:
open()
: Kaldes, når en ny WebSocket-forbindelse etableres.on_message(message)
: Kaldes, når en besked modtages fra klienten.on_close()
: Kaldes, når WebSocket-forbindelsen lukkes.
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:
- Cookie-baseret godkendelse: Gem brugeroplysninger i cookies.
- Tredjeparts-godkendelse (OAuth): Integrer med populære sociale medieplatforme som Google, Facebook og Twitter.
- API-nøgler: Brug API-nøgler til at godkende API-anmodninger.
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:
- Beskyttelse mod Cross-Site Scripting (XSS): Tornado undslipper automatisk HTML-entiteter for at forhindre XSS-angreb. Brug altid
render()
-metoden til at rendere skabeloner og undgå at generere HTML direkte i dine request-handlere. - Beskyttelse mod Cross-Site Request Forgery (CSRF): Aktiver CSRF-beskyttelse i dine applikationsindstillinger for at forhindre CSRF-angreb.
- HTTPS: Brug altid HTTPS til at kryptere kommunikationen mellem serveren og klienter.
- Inputvalidering: Valider alt brugerinput for at forhindre injektionsangreb og andre sårbarheder.
- Regelmæssige sikkerhedsrevisioner: Gennemfør regelmæssige sikkerhedsrevisioner for at identificere og adressere potentielle sårbarheder.
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:
- Brug en produktionsklar Event Loop: Brug en produktionsklar event loop som
uvloop
for forbedret ydeevne. - Aktiver gzip-komprimering: Aktiver gzip-komprimering for at reducere størrelsen på HTTP-svar.
- Cache statiske filer: Cache statiske filer for at reducere belastningen på serveren.
- Overvåg ydeevne: Overvåg ydeevnen af din applikation ved hjælp af værktøjer som New Relic eller Prometheus.
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:
- **Tegnkodning:** Brug altid UTF-8-kodning for at understøtte et bredt udvalg af tegn.
- **Dato- og tidsformatering:** Brug lokalespecifik dato- og tidsformatering. Pythons `strftime`- og `strptime`-funktioner kan bruges med sprogindstillinger.
- **Talformatering:** Brug lokalespecifik talformatering (f.eks. decimal- og tusindtalsseparatorer). `locale`-modulet tilbyder funktioner til dette.
- **Valutaformatering:** Brug lokalespecifik valutaformatering. Overvej at bruge et bibliotek som `Babel` til mere avanceret valutahåndtering.
- **Højre-til-venstre (RTL) sprog:** Understøt RTL-sprog som arabisk og hebraisk. Dette kan indebære at spejle layoutet på din hjemmeside.
- **Oversættelseskvalitet:** Brug professionelle oversættere for at sikre nøjagtige og kulturelt passende oversættelser. Maskinoversættelse kan være et godt udgangspunkt, men kræver ofte menneskelig gennemgang.
- **Brugerens sprogindstilling:** Implementer robust detektering af sprogindstilling baseret på brugerpræferencer, browserindstillinger eller IP-adresse. Giv brugerne en måde manuelt at vælge deres foretrukne sprog.
- **Testning:** Test din applikation grundigt med forskellige sprogindstillinger for at sikre, at alt vises korrekt.
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!