En dyptgående utforskning av Tornado, et Python-nettrammeverk og asynkront nettverksbibliotek. Lær å bygge skalerbare, høytytende applikasjoner med detaljerte forklaringer, eksempler og beste praksis.
Tornado-dokumentasjon: En omfattende guide for utviklere over hele verden
Tornado er et Python-nettrammeverk og asynkront nettverksbibliotek, opprinnelig utviklet hos FriendFeed. Det er spesielt godt egnet for long-polling, WebSockets og andre applikasjoner som krever en langvarig tilkobling til hver bruker. Dets ikke-blokkerende nettverks-I/O gjør det ekstremt skalerbart og til et kraftig valg for å bygge høytytende nettapplikasjoner. Denne omfattende guiden vil lede deg gjennom Tornados kjernekonsepter og gi praktiske eksempler for å komme i gang.
Hva er Tornado?
I kjernen er Tornado et nettrammeverk og asynkront nettverksbibliotek. I motsetning til tradisjonelle synkrone nettrammeverk, bruker Tornado en enkelttrådet, hendelsesløkkebasert arkitektur. Dette betyr at det kan håndtere mange samtidige tilkoblinger uten å kreve en tråd per tilkobling, noe som gjør det mer effektivt og skalerbart.
Nøkkelfunksjoner i Tornado:
- Asynkron nettverksbygging: Tornados kjerne er bygget rundt asynkron I/O, noe som gjør at den kan håndtere tusenvis av samtidige tilkoblinger effektivt.
- Nettrammeverk: Det inkluderer funksjoner som forespørselshåndterere, ruting, maler og autentisering, noe som gjør det til et komplett nettrammeverk.
- WebSocket-støtte: Tornado gir utmerket støtte for WebSockets, noe som muliggjør sanntidskommunikasjon mellom serveren og klientene.
- Lettvektig og rask: Tornado er designet for ytelse, er lettvektig og effektivt, minimerer overhead og maksimerer gjennomstrømning.
- Enkel å bruke: Til tross for sine avanserte funksjoner er Tornado relativt enkel å lære og bruke, med en klar og veldokumentert API.
Sette opp ditt Tornado-miljø
Før du dykker inn i Tornado-utvikling, må du sette opp miljøet ditt. Her er en trinn-for-trinn-guide:
- Installer Python: Sørg for at du har Python 3.6 eller høyere installert. Du kan laste det ned fra den offisielle Python-nettsiden (python.org).
- Opprett et virtuelt miljø (anbefalt): Bruk
venv
ellervirtualenv
for å opprette et isolert miljø for prosjektet ditt:python3 -m venv myenv source myenv/bin/activate # På Linux/macOS myenv\Scripts\activate # På Windows
- Installer Tornado: Installer Tornado ved hjelp av pip:
pip install tornado
Din første Tornado-applikasjon
La oss lage en enkel "Hello, World!"-applikasjon med Tornado. Opprett en fil med navnet app.py
og legg til 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()
Kjør nå applikasjonen fra terminalen din:
python app.py
Åpne nettleseren din og naviger til http://localhost:8888
. Du skal se meldingen "Hello, World!".
Forklaring:
tornado.ioloop
: Kjernehendelsesløkken som håndterer asynkrone operasjoner.tornado.web
: Tilbyr nettrammeverkskomponentene, som forespørselshåndterere og ruting.MainHandler
: En forespørselshåndterer som definerer hvordan innkommende HTTP-forespørsler skal håndteres.get()
-metoden kalles for GET-forespørsler.tornado.web.Application
: Oppretter Tornado-applikasjonen, og kobler URL-mønstre til forespørselshåndterere.app.listen(8888)
: Starter serveren, som lytter etter innkommende tilkoblinger på port 8888.tornado.ioloop.IOLoop.current().start()
: Starter hendelsesløkken, som behandler innkommende forespørsler og håndterer asynkrone operasjoner.
Forespørselshåndterere og ruting
Forespørselshåndterere er grunnlaget for Tornado-nettapplikasjoner. De definerer hvordan man håndterer innkommende HTTP-forespørsler basert på URL-en. Ruting kobler URL-er til spesifikke forespørselshåndterere.
Definere forespørselshåndterere:
For å lage en forespørselshåndterer, arver du fra tornado.web.RequestHandler
og implementerer de aktuelle HTTP-metodene (get
, post
, put
, delete
, etc.).
class MyHandler(tornado.web.RequestHandler):
def get(self):
self.write("Dette er en GET-forespørsel.")
def post(self):
data = self.request.body.decode('utf-8')
self.write(f"Mottok POST-data: {data}")
Ruting:
Ruting konfigureres når du oppretter tornado.web.Application
. Du gir en liste med tupler, der hvert tuppel inneholder et URL-mønster og den tilsvarende forespørselshåndtereren.
app = tornado.web.Application([
(r"/", MainHandler),
(r"/myhandler", MyHandler),
])
URL-mønstre:
URL-mønstre er regulære uttrykk. Du kan bruke grupper i regulære uttrykk for å fange opp deler av URL-en og sende dem som argumenter til metodene i forespørselshåndtereren.
class UserHandler(tornado.web.RequestHandler):
def get(self, user_id):
self.write(f"Bruker-ID: {user_id}")
app = tornado.web.Application([
(r"/user/([0-9]+)", UserHandler),
])
I dette eksemplet matcher /user/([0-9]+)
URL-er som /user/123
. Delen ([0-9]+)
fanger opp ett eller flere siffer og sender dem som user_id
-argumentet til get
-metoden i UserHandler
.
Maler (Templating)
Tornado inkluderer en enkel og effektiv malmotor. Maler brukes til å generere HTML dynamisk, og skiller presentasjonslogikk fra applikasjonslogikk.
Opprette maler:
Maler lagres vanligvis i separate filer (f.eks. index.html
). Her er et enkelt eksempel:
<!DOCTYPE html>
<html>
<head>
<title>Min Nettside</title>
</head>
<body>
<h1>Velkommen, {{ name }}!</h1>
<p>I dag er det {{ today }}.</p>
</body>
</html>
{{ name }}
og {{ today }}
er plassholdere som vil bli erstattet med faktiske verdier når malen gjengis.
Gjengi maler:
For å gjengi en mal, bruk render()
-metoden i forespørselshåndtereren din:
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
-innstillingen er riktig konfigurert i applikasjonsinnstillingene dine. Som standard ser Tornado etter maler i en katalog som heter templates
i samme katalog som applikasjonsfilen din.
app = tornado.web.Application([
(r"/template", TemplateHandler),
], template_path="templates")
Malsyntaks:
Tornado-maler støtter ulike funksjoner, inkludert:
- Variabler:
{{ variable }}
- Kontrollflyt:
{% if condition %} ... {% else %} ... {% end %}
,{% for item in items %} ... {% end %}
- Funksjoner:
{{ function(argument) }}
- Inkluderinger:
{% include "another_template.html" %}
- Escaping: Tornado unnslipper automatisk HTML-entiteter for å forhindre cross-site scripting (XSS)-angrep. Du kan deaktivere escaping ved å bruke
{% raw variable %}
.
Asynkrone operasjoner
Tornados styrke ligger i dens asynkrone kapabiliteter. Asynkrone operasjoner lar applikasjonen din utføre ikke-blokkerende I/O, noe som forbedrer ytelse og skalerbarhet. Dette er spesielt nyttig for oppgaver som involverer venting på eksterne ressurser, som databasespørringer eller nettverksforespørsler.
@tornado.gen.coroutine
:
Dekoratøren @tornado.gen.coroutine
lar deg skrive asynkron kode ved å bruke yield
-nøkkelordet. Dette gjør at asynkron kode ser ut og oppfører seg mer som synkron kode, noe som forbedrer lesbarheten og vedlikeholdbarheten.
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 eksemplet er http_client.fetch()
en asynkron operasjon som returnerer en Future
. yield
-nøkkelordet suspenderer utførelsen av korutinen til Future
-en er løst. Når Future
-en er løst, gjenopptas korutinen og responskroppen skrives til klienten.
tornado.concurrent.Future
:
En Future
representerer resultatet av en asynkron operasjon som kanskje ikke er tilgjengelig ennå. Du kan bruke Future
-objekter for å kjede sammen asynkrone operasjoner og håndtere feil.
tornado.ioloop.IOLoop
:
IOLoop
er hjertet i Tornados asynkrone motor. Den overvåker filbeskrivelser og sockets for hendelser og sender dem til de riktige håndtererne. Du trenger vanligvis ikke å samhandle direkte med IOLoop
, men det er viktig å forstå dens rolle i håndteringen av asynkrone operasjoner.
WebSockets
Tornado gir utmerket støtte for WebSockets, noe som muliggjør sanntidskommunikasjon mellom serveren og klientene. WebSockets er ideelle for applikasjoner som krever toveis kommunikasjon med lav latens, som chat-applikasjoner, online-spill og sanntids-dashboards.
Opprette en WebSocket-håndterer:
For å opprette en WebSocket-håndterer, arver du fra tornado.websocket.WebSocketHandler
og implementerer følgende metoder:
open()
: Kalles når en ny WebSocket-tilkobling etableres.on_message(message)
: Kalles når en melding mottas fra klienten.on_close()
: Kalles når WebSocket-tilkoblingen lukkes.
import tornado.websocket
class WebSocketHandler(tornado.websocket.WebSocketHandler):
def open(self):
print("WebSocket åpnet")
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 # Aktiver kryss-opprinnelse WebSocket-tilkoblinger
Integrere WebSockets i applikasjonen din:
Legg til WebSocket-håndtereren i applikasjonens rutingskonfigurasjon:
app = tornado.web.Application([
(r"/ws", WebSocketHandler),
])
Klient-side implementering:
På klientsiden kan du bruke JavaScript for å etablere en WebSocket-tilkobling og sende/motta meldinger:
const websocket = new WebSocket("ws://localhost:8888/ws");
websocket.onopen = () => {
console.log("WebSocket-tilkobling etablert");
websocket.send("Hei fra klienten!");
};
websocket.onmessage = (event) => {
console.log("Mottok melding:", event.data);
};
websocket.onclose = () => {
console.log("WebSocket-tilkobling lukket");
};
Autentisering og sikkerhet
Sikkerhet er et kritisk aspekt ved utvikling av nettapplikasjoner. Tornado tilbyr flere funksjoner for å hjelpe deg med å sikre applikasjonene dine, inkludert autentisering, autorisasjon og beskyttelse mot vanlige nettsårbarheter.
Autentisering:
Autentisering er prosessen med å verifisere identiteten til en bruker. Tornado gir innebygd støtte for ulike autentiseringsordninger, inkludert:
- Cookie-basert autentisering: Lagre brukerlegitimasjon i informasjonskapsler (cookies).
- Tredjepartsautentisering (OAuth): Integrer med populære sosiale medieplattformer som Google, Facebook og Twitter.
- API-nøkler: Bruk API-nøkler for å autentisere API-forespørsler.
Autorisasjon:
Autorisasjon er prosessen med å bestemme om en bruker har tillatelse til å få tilgang til en bestemt ressurs. Du kan implementere autorisasjonslogikk i dine forespørselshåndterere for å begrense tilgang basert på brukerroller eller tillatelser.
Beste praksis for sikkerhet:
- Beskyttelse mot Cross-Site Scripting (XSS): Tornado unnslipper automatisk HTML-entiteter for å forhindre XSS-angrep. Bruk alltid
render()
-metoden for å gjengi maler og unngå å generere HTML direkte i dine forespørselshåndterere. - Beskyttelse mot Cross-Site Request Forgery (CSRF): Aktiver CSRF-beskyttelse i applikasjonsinnstillingene for å forhindre CSRF-angrep.
- HTTPS: Bruk alltid HTTPS for å kryptere kommunikasjonen mellom serveren og klientene.
- Input-validering: Valider all brukerinput for å forhindre injeksjonsangrep og andre sårbarheter.
- Regelmessige sikkerhetsrevisjoner: Gjennomfør regelmessige sikkerhetsrevisjoner for å identifisere og adressere potensielle sårbarheter.
Utrulling (Deployment)
Å rulle ut en Tornado-applikasjon innebærer flere trinn, inkludert konfigurering av en webserver, oppsett av en prosessbehandler og optimalisering av ytelse.
Webserver:
Du kan rulle ut Tornado bak en webserver som Nginx eller Apache. Webserveren fungerer som en omvendt proxy, og videresender innkommende forespørsler til Tornado-applikasjonen.
Prosessbehandler:
En prosessbehandler som Supervisor eller systemd kan brukes til å administrere Tornado-prosessen, og sikre at den automatisk startes på nytt hvis den krasjer.
Ytelsesoptimalisering:
- Bruk en produksjonsklar hendelsesløkke: Bruk en produksjonsklar hendelsesløkke som
uvloop
for forbedret ytelse. - Aktiver gzip-komprimering: Aktiver gzip-komprimering for å redusere størrelsen på HTTP-responser.
- Cache statiske filer: Cache statiske filer for å redusere belastningen på serveren.
- Overvåk ytelse: Overvåk ytelsen til applikasjonen din ved hjelp av verktøy som New Relic eller Prometheus.
Internasjonalisering (i18n) og lokalisering (l10n)
Når man bygger applikasjoner for et globalt publikum, er det viktig å vurdere internasjonalisering (i18n) og lokalisering (l10n). i18n er prosessen med å designe en applikasjon slik at den kan tilpasses ulike språk og regioner uten tekniske endringer. l10n er prosessen med å tilpasse en internasjonalisert applikasjon for et spesifikt språk eller en region ved å legge til lokale-spesifikke komponenter og oversette tekst.
Tornado og i18n/l10n
Tornado selv har ikke innebygde i18n/l10n-biblioteker. Du kan imidlertid enkelt integrere standard Python-biblioteker som `gettext` eller mer sofistikerte rammeverk som Babel for å håndtere i18n/l10n i din Tornado-applikasjon.
Eksempel med `gettext`:
1. **Sett opp dine lokalinnstillinger (locales):** Opprett kataloger for hvert språk du vil støtte, som inneholder meldingskataloger (vanligvis `.mo`-filer).
locales/
en/LC_MESSAGES/messages.mo
fr/LC_MESSAGES/messages.mo
de/LC_MESSAGES/messages.mo
2. **Trekk ut oversettbare strenger:** Bruk et verktøy som `xgettext` for å trekke ut oversettbare strenger fra Python-koden din til en `.po`-fil (Portable Object). Denne filen vil inneholde de originale strengene og plassholdere for oversettelser.
xgettext -d messages -o locales/messages.po your_tornado_app.py
3. **Oversett strengene:** Oversett strengene i `.po`-filene for hvert språk.
4. **Kompiler oversettelsene:** Kompiler `.po`-filene til `.mo`-filer (Machine Object) som brukes av `gettext` under kjøring.
msgfmt locales/fr/LC_MESSAGES/messages.po -o locales/fr/LC_MESSAGES/messages.mo
5. **Integrer i din Tornado-applikasjon:**
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 tilfeller der lokalinnstillingen ikke støttes av systemet
print(f"Lokalinnstilling {self.get_user_locale().code} støttes ikke")
translation = gettext.translation('messages', 'locales', languages=[self.get_user_locale().code])
translation.install()
self._ = translation.gettext
def get_current_user_locale(self):
# Logikk for å bestemme brukerens lokalinnstilling (f.eks. fra Accept-Language-header, brukerinnstillinger, etc.)
# Dette er et forenklet eksempel - du trenger en mer 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. **Endre malene dine:** Bruk `_()`-funksjonen (bundet til `gettext.gettext`) for å merke strenger for oversettelse i malene dine.
<h1>{{ _("Velkommen til nettsiden vår!") }}</h1>
<p>{{ _("Dette er et oversatt avsnitt.") }}</p>
Viktige hensyn for et globalt publikum:
- **Tegnkoding:** Bruk alltid UTF-8-koding for å støtte et bredt spekter av tegn.
- **Dato- og tidsformatering:** Bruk lokale-spesifikk dato- og tidsformatering. Pythons `strftime`- og `strptime`-funksjoner kan brukes med lokale-innstillinger.
- **Tallformatering:** Bruk lokale-spesifikk tallformatering (f.eks. desimalskilletegn, tusenskilletegn). `locale`-modulen tilbyr funksjoner for dette.
- **Valutaformatering:** Bruk lokale-spesifikk valutaformatering. Vurder å bruke et bibliotek som `Babel` for mer avansert valutahåndtering.
- **Høyre-til-venstre (RTL) språk:** Støtt RTL-språk som arabisk og hebraisk. Dette kan innebære å speile layouten på nettstedet ditt.
- **Oversettelseskvalitet:** Bruk profesjonelle oversettere for å sikre nøyaktige og kulturelt passende oversettelser. Maskinoversettelse kan være et godt utgangspunkt, men det krever ofte menneskelig gjennomgang.
- **Gjenkjenning av brukerens lokale:** Implementer robust gjenkjenning av lokale basert på brukerpreferanser, nettleserinnstillinger eller IP-adresse. Gi brukerne en måte å manuelt velge sitt foretrukne språk.
- **Testing:** Test applikasjonen din grundig med forskjellige lokalinnstillinger for å sikre at alt vises korrekt.
Avanserte emner
Egendefinerte feilsider:
Du kan tilpasse feilsidene som Tornado viser når en feil oppstår. Dette lar deg gi en mer brukervennlig opplevelse og inkludere feilsøkingsinformasjon.
Egendefinerte innstillinger:
Du kan definere egendefinerte innstillinger i applikasjonskonfigurasjonen og få tilgang til dem i dine forespørselshåndterere. Dette er nyttig for å lagre applikasjonsspesifikke parametere, som tilkoblingsstrenger til databaser eller API-nøkler.
Testing:
Test dine Tornado-applikasjoner grundig for å sikre at de fungerer korrekt og sikkert. Bruk enhetstester, integrasjonstester og ende-til-ende-tester for å dekke alle aspekter av applikasjonen din.
Konklusjon
Tornado er et kraftig og allsidig nettrammeverk som er godt egnet for å bygge skalerbare, høytytende nettapplikasjoner. Dets asynkrone arkitektur, WebSocket-støtte og brukervennlige API gjør det til et populært valg for utviklere over hele verden. Ved å følge retningslinjene og eksemplene i denne omfattende guiden, kan du begynne å bygge dine egne Tornado-applikasjoner og dra nytte av dens mange funksjoner.
Husk å konsultere den offisielle Tornado-dokumentasjonen for den mest oppdaterte informasjonen og beste praksis. God koding!