Norsk

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:

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:

  1. 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).
  2. Opprett et virtuelt miljø (anbefalt): Bruk venv eller virtualenv for å opprette et isolert miljø for prosjektet ditt:
    python3 -m venv myenv
    source myenv/bin/activate  # På Linux/macOS
    myenv\Scripts\activate  # På Windows
  3. 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:

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:

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:

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:

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:

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:

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:

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!